<script lang="ts">
  import { success, error as toastError } from "$lib/stores/toasts";
  import { createEventDispatcher } from "svelte";
  import { fade } from "svelte/transition";
  import { normalizeDigits } from "$lib/utils/phone";
  import { colorForGroup } from "$lib/utils/groupColor";
  import TaskDueBadge from "$lib/ui/data/task/TaskDueBadge.svelte";
  import TaskAssignees from "$lib/ui/data/task/TaskAssignees.svelte";
  import TaskCompleteButton from "$lib/ui/data/task/TaskCompleteButton.svelte";
  import TaskActions from "$lib/ui/data/task/TaskActions.svelte";
  import TaskText from "$lib/ui/data/task/TaskText.svelte";
  import TaskMeta from "$lib/ui/data/task/TaskMeta.svelte";

  export let id: number;
  export let description: string;
  export let due_date: string | null = null;
  export let display_code: number | null = null;
  export let assignees: string[] = [];
  export let currentUserId: string | null | undefined = null;
  export let completed: boolean = false;
  export let completed_at: string | null = null;
  export let groupName: string | null = null;
  export let groupId: string | null = null;

  const dispatch = createEventDispatcher<{
    changed: { id: number; action: string; patch: any };
  }>();

  const code = display_code ?? id;
  const codeStr = String(code).padStart(4, "0");
  $: isAssigned =
    !!currentUserId &&
    assignees.some(
      (a) => normalizeDigits(a) === normalizeDigits(currentUserId),
    );
  // Derivados de fecha ahora los maneja TaskDueBadge
  $: groupLabel = groupName != null ? groupName : "Personal";
  $: gc = groupId ? colorForGroup(groupId) : null;

  let editing = false;
  let dateValue: string = due_date ?? "";
  let busy = false;

  // Popover de responsables
  $: assigneesCount = Array.isArray(assignees) ? assignees.length : 0;
  $: canUnassign = !(groupId == null && assigneesCount === 1 && isAssigned);

  // Edición de texto (inline)
  let editingText = false;
  let taskText: any | null = null;

  async function doClaim() {
    if (busy) return;
    busy = true;
    try {
      const res = await fetch(`/api/tasks/${id}/claim`, { method: "POST" });
      if (res.ok) {
        // Actualizar estado local (añadirte si no estabas)
        if (currentUserId) {
          const set = new Set<string>(assignees || []);
          set.add(String(currentUserId));
          assignees = Array.from(set);
        }
        success("Tarea reclamada");
        dispatch("changed", { id, action: "claim", patch: { assignees } });
      } else {
        const txt = await res.text();
        toastError(txt || "No se pudo reclamar");
      }
    } catch (e) {
      toastError("Error de red");
    } finally {
      busy = false;
    }
  }

  function toIsoSqlLocal(d: Date = new Date()): string {
    const iso = d.toISOString();
    return iso.substring(0, 23).replace("T", " ");
  }

  async function doComplete() {
    if (busy || completed) return;
    busy = true;
    try {
      const hadNoAssignees = assigneesCount === 0;
      const res = await fetch(`/api/tasks/${id}/complete`, { method: "POST" });
      if (res.ok) {
        const data = await res.json().catch(() => null);
        const newCompletedAt: string | null = data?.task?.completed_at
          ? String(data.task.completed_at)
          : toIsoSqlLocal(new Date());
        // Si no tenía responsables, el backend te auto-asigna: reflejarlo localmente
        if (hadNoAssignees && currentUserId) {
          const set = new Set<string>(assignees || []);
          set.add(String(currentUserId));
          assignees = Array.from(set);
        }
        completed = true;
        completed_at = newCompletedAt;
        success(
          hadNoAssignees
            ? "Te has asignado y completado la tarea"
            : "Tarea completada",
        );
        dispatch("changed", {
          id,
          action: "complete",
          patch: { completed: true, completed_at, assignees },
        });
      } else {
        const txt = await res.text();
        toastError(txt || "No se pudo completar la tarea");
      }
    } catch {
      toastError("Error de red");
    } finally {
      busy = false;
    }
  }

  async function doUncomplete() {
    if (busy || !completed) return;
    busy = true;
    try {
      const res = await fetch(`/api/tasks/${id}/uncomplete`, {
        method: "POST",
      });
      if (res.ok) {
        await res.json().catch(() => null);
        completed = false;
        completed_at = null;
        success("Tarea reabierta");
        dispatch("changed", {
          id,
          action: "uncomplete",
          patch: { completed: false, completed_at: null },
        });
      } else {
        const txt = await res.text();
        toastError(txt || "No se pudo deshacer completar");
      }
    } catch {
      toastError("Error de red");
    } finally {
      busy = false;
    }
  }

  async function doUnassign() {
    if (busy) return;
    busy = true;
    try {
      const res = await fetch(`/api/tasks/${id}/unassign`, { method: "POST" });
      if (res.ok) {
        if (currentUserId) {
          const after = (assignees || []).filter(
            (a) =>
              normalizeDigits(a) !== normalizeDigits(String(currentUserId)),
          );
          assignees = after;
        }
        success("Asignación eliminada");
        dispatch("changed", { id, action: "unassign", patch: { assignees } });
      } else {
        const txt = await res.text();
        toastError(txt || "No se pudo soltar");
      }
    } catch {
      toastError("Error de red");
    } finally {
      busy = false;
    }
  }

  async function saveDate(value: string | null) {
    if (busy) return;
    busy = true;
    try {
      const body = { due_date: value };
      const res = await fetch(`/api/tasks/${id}`, {
        method: "PATCH",
        headers: { "content-type": "application/json" },
        body: JSON.stringify(body),
      });
      if (res.ok) {
        due_date = body.due_date;
        success("Fecha actualizada");
        dispatch("changed", { id, action: "update_due", patch: { due_date } });
        editing = false;
        dateValue = due_date ?? "";
      } else {
        const txt = await res.text();
        toastError(txt || "No se pudo actualizar la fecha");
      }
    } catch {
      toastError("Error de red");
    } finally {
      busy = false;
    }
  }

  function toggleEdit() {
    editing = !editing;
    if (editing) editingText = false;
    dateValue = due_date ?? "";
  }

  function clearDate() {
    if (busy) return;
    if (!confirm("¿Quitar la fecha de vencimiento?")) return;
    saveDate(null);
  }

  function toggleEditText() {
    editingText = !editingText;
    if (editingText) {
      editing = false;
    }
  }

  async function saveText(text?: string) {
    if (busy) return;
    const rawSource =
      typeof text === "string" ? text : (taskText?.getCurrentText?.() ?? "");
    const raw = String(rawSource).replace(/\s+/g, " ").trim();
    if (raw.length < 1 || raw.length > 1000) {
      toastError("La descripción debe tener entre 1 y 1000 caracteres.");
      return;
    }
    if (raw === description) {
      editingText = false;
      return;
    }
    busy = true;
    try {
      const res = await fetch(`/api/tasks/${id}`, {
        method: "PATCH",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({ description: raw }),
      });
      if (res.ok) {
        description = raw;
        success("Descripción actualizada");
        dispatch("changed", {
          id,
          action: "update_desc",
          patch: { description },
        });
        editingText = false;
      } else {
        const txt = await res.text();
        toastError(txt || "No se pudo actualizar la descripción");
      }
    } catch {
      toastError("Error de red");
    } finally {
      busy = false;
    }
  }

  function cancelText() {
    editingText = false;
  }
</script>

<li
  class="task"
  class:completed
  in:fade={{ duration: 180 }}
  out:fade={{ duration: 180 }}
>
  <div class="code">{codeStr}</div>
  <TaskText
    {description}
    {completed}
    editing={editingText}
    {busy}
    bind:this={taskText}
    on:toggleEdit={toggleEditText}
    on:saveText={(e) =>
      saveText((e as CustomEvent<{ text: string }>).detail.text)}
    on:cancelText={cancelText}
  />

  <div class="meta">
    <TaskMeta {groupLabel} {gc} {due_date} />
  </div>
  <div class="complete">
    <TaskCompleteButton
      {completed}
      {busy}
      on:complete={doComplete}
      on:uncomplete={doUncomplete}
    />
  </div>
  <div class="assignees-container">
    <TaskAssignees {id} {assignees} {currentUserId} />
  </div>
  <div class="actions">
    <TaskActions
      {isAssigned}
      {canUnassign}
      {busy}
      {completed}
      {editingText}
      editingDate={editing}
      {dateValue}
      on:claim={doClaim}
      on:unassign={doUnassign}
      on:toggleEditText={toggleEditText}
      on:saveText={saveText}
      on:cancelText={cancelText}
      on:toggleEditDate={toggleEdit}
      on:saveDate={(e) =>
        saveDate((e as CustomEvent<{ value: string | null }>).detail.value)}
      on:clearDate={clearDate}
      on:cancelDate={() => (editing = false)}
    />
  </div>
</li>

<style>
  .task {
    display: grid;
    grid-template-columns: 1fr max-content;
    grid-template-rows: min-content max-content max-content max-content;
    grid-gap: 2px;
    padding: 4px 0 8px 0;
    border-bottom: 2px dashed var(--color-border);
    position: relative;
    margin: 0 0 4px 0;
  }
  .task:last-child {
    border-bottom: 0;
  }
  .code {
    font-weight: 300;
    font-size: 0.8rem;
    color: var(--color-text-muted);
    font-family: monospace;
    letter-spacing: 0.5px;
    grid-row: 1/2;
    grid-column: 1/2;
    align-self: center;
  }
  .completed {
    opacity: 0.5;
  }
  .meta {
    justify-self: end;
    align-items: start;
    grid-row: 1/2;
    grid-column: 2/3;
    display: inline-flex;
    gap: 6px;
    align-items: center;
  }
  .assignees-container {
    grid-row: 4/5;
    grid-column: 1/2;
  }
  .task.completed {
    opacity: 0.7;
  }
  .complete {
    grid-row: 3/4;
    grid-column: 2/3;
    justify-self: end;
  }
  .actions {
    justify-self: stretch;
    grid-column: 2/3;
    grid-row: 4/5;
    margin: 2px 0 4px 0;
    display: flex;
    flex-wrap: nowrap;
    gap: 6px;
    align-items: center;
    justify-content: flex-end;
  }
  :global(.task .btn.primary svg) {
    margin-right: 8px;
  }
  :global(.task .icon-btn svg) {
    margin-right: 8px;
  }
  @media (max-width: 768px) {
    .actions {
      justify-self: stretch;
    }
    /* Botón de completar a ancho completo en mobile */
    .complete {
      grid-column: 1/3;
      justify-self: stretch;
    }
  }
  @media (max-width: 480px) {
    .task {
      grid-template-columns: 1fr;
    }
    .meta {
      justify-self: end;
    }
    /* En 1 columna, colocamos acciones en una fila propia bajo el badge */
    .actions {
      grid-row: 4/5;
      grid-column: 1/3;
      justify-self: flex-end;
    }
  }

  /* Badge de responsables */
</style>
