/**
 * "Sprints" tab of the web workspace (ticket #86): create, rename, reorder
 * (Monter/Descendre — no drag-and-drop required) and delete sprints, plus
 * add/remove tickets via the mobile-adapted ticket picker. A dedicated surface
 * — not an overlay above the ticket list like the desktop `SprintManager` —
 * reachable directly from the project tab bar.
 *
 * Reuses `useTickets` (sprint CRUD) and `useTicketSearch` (to resolve which
 * tickets belong to a sprint client-side, exactly like the desktop
 * `SprintManager` — `ticket_list` has no server-side `sprintId` filter). The
 * per-sprint ticket list also lets the user remove a ticket from the sprint
 * (`assignSprint(ref, null)`, which routes to `ticket_unassign_sprint`) — the
 * symmetric counterpart of "Ajouter tickets" (QA #86 fix).
 */

import { useState } from "react";

import type { Sprint, TicketSummary } from "@/domain";
import { useTickets, useTicketSearch, type TicketsViewModel } from "@/features/tickets";
import { Button, Input, Panel, Spinner } from "@/shared";
import { WebConfirmDialog } from "./WebConfirmDialog";
import { WebTicketPickerSheet } from "./WebTicketPickerSheet";

export interface WebSprintsViewProps {
  projectId: string;
  /** Switches to the Tickets tab, optionally pre-filtered to one sprint. */
  onViewSprintTickets: (sprintId: string) => void;
}

export function WebSprintsView({ projectId, onViewSprintTickets }: WebSprintsViewProps) {
  const vm = useTickets(projectId);
  // Independent of the Tickets tab's own query (mirrors desktop SprintManager):
  // used to resolve which refs already belong to a sprint, both for the
  // compact per-sprint ticket list and the "ajouter des tickets" exclude set.
  const search = useTicketSearch(projectId, { refreshOnEvents: true });

  const [showCreate, setShowCreate] = useState(false);
  const [newName, setNewName] = useState("");
  const [renamingId, setRenamingId] = useState<string | null>(null);
  const [renameDraft, setRenameDraft] = useState("");
  const [confirmDelete, setConfirmDelete] = useState<{ id: string; name: string } | null>(null);
  const [pickerSprint, setPickerSprint] = useState<{ id: string; name: string } | null>(null);

  const sprints = [...vm.sprints].sort((a, b) => a.order - b.order);

  async function handleCreate(e: React.FormEvent) {
    e.preventDefault();
    const name = newName.trim();
    if (!name) return;
    const created = await vm.createSprint(name);
    if (created) {
      setNewName("");
      setShowCreate(false);
    }
  }

  return (
    <Panel
      title="Sprints"
      actions={
        <Button size="sm" onClick={() => setShowCreate((v) => !v)}>
          + Sprint
        </Button>
      }
    >
      {vm.error && (
        <p role="alert" className="mb-3 rounded-md border border-danger/40 bg-danger/10 px-3 py-2 text-sm text-danger">
          {vm.error}
        </p>
      )}

      {showCreate && (
        <form onSubmit={handleCreate} className="mb-3 flex flex-col gap-2 rounded-md border border-border bg-raised/50 p-2">
          <label className="flex flex-col gap-1">
            <span className="text-xs font-medium text-muted">Nom du sprint</span>
            <Input
              aria-label="Nom du sprint"
              value={newName}
              onChange={(e) => setNewName(e.target.value)}
              autoFocus
            />
          </label>
          <div className="flex justify-end gap-2">
            <Button type="button" size="sm" variant="ghost" onClick={() => setShowCreate(false)}>
              Annuler
            </Button>
            <Button type="submit" size="sm" disabled={!newName.trim() || vm.busy}>
              Créer
            </Button>
          </div>
        </form>
      )}

      {vm.busy && vm.sprints.length === 0 ? (
        <span className="inline-flex items-center gap-1.5 text-sm text-muted">
          <Spinner size={12} /> Chargement des sprints…
        </span>
      ) : sprints.length === 0 ? (
        <div className="flex flex-col items-start gap-2">
          <p className="text-sm text-muted">Aucun sprint.</p>
          <Button size="sm" onClick={() => setShowCreate(true)}>
            Créer un sprint
          </Button>
        </div>
      ) : (
        <ul className="flex flex-col gap-3">
          {sprints.map((sprint, index) => (
            <SprintCard
              key={sprint.id}
              sprint={sprint}
              index={index}
              lastIndex={sprints.length - 1}
              tickets={search.rows.filter((t) => t.sprintId === sprint.id)}
              vm={vm}
              renaming={renamingId === sprint.id}
              renameDraft={renameDraft}
              onStartRename={() => {
                setRenamingId(sprint.id);
                setRenameDraft(sprint.name);
              }}
              onRenameDraftChange={setRenameDraft}
              onCancelRename={() => setRenamingId(null)}
              onSaveRename={async () => {
                const ok = await vm.renameSprint(sprint.id, renameDraft.trim());
                if (ok) setRenamingId(null);
              }}
              onViewTickets={() => onViewSprintTickets(sprint.id)}
              onAddTickets={() => setPickerSprint({ id: sprint.id, name: sprint.name })}
              onRequestDelete={() => setConfirmDelete({ id: sprint.id, name: sprint.name })}
            />
          ))}
        </ul>
      )}

      {confirmDelete && (
        <WebConfirmDialog
          title={`Supprimer le sprint « ${confirmDelete.name} » ?`}
          body="Les tickets de ce sprint seront conservés et passeront en « Sans sprint »."
          confirmLabel="Supprimer"
          busy={vm.busy}
          onCancel={() => setConfirmDelete(null)}
          onConfirm={async () => {
            await vm.deleteSprint(confirmDelete.id);
            setConfirmDelete(null);
          }}
        />
      )}

      {pickerSprint && (
        <WebTicketPickerSheet
          projectId={projectId}
          title={`Ajouter des tickets au sprint « ${pickerSprint.name} »`}
          confirmLabel="Ajouter au sprint"
          selectionMode="multi"
          excludeRefs={search.rows.filter((t) => t.sprintId === pickerSprint.id).map((t) => t.ref)}
          onSelect={(result) => {
            const picked = Array.isArray(result) ? result : [result];
            for (const p of picked) void vm.assignSprint(p.ref, pickerSprint.id);
          }}
          onClose={() => setPickerSprint(null)}
        />
      )}
    </Panel>
  );
}

interface SprintCardProps {
  sprint: Sprint;
  index: number;
  lastIndex: number;
  tickets: TicketSummary[];
  vm: TicketsViewModel;
  renaming: boolean;
  renameDraft: string;
  onStartRename: () => void;
  onRenameDraftChange: (value: string) => void;
  onCancelRename: () => void;
  onSaveRename: () => Promise<void>;
  onViewTickets: () => void;
  onAddTickets: () => void;
  onRequestDelete: () => void;
}

function SprintCard({
  sprint,
  index,
  lastIndex,
  tickets,
  vm,
  renaming,
  renameDraft,
  onStartRename,
  onRenameDraftChange,
  onCancelRename,
  onSaveRename,
  onViewTickets,
  onAddTickets,
  onRequestDelete,
}: SprintCardProps) {
  return (
    <li className="rounded-md border border-border p-3">
      <div className="flex items-center justify-between gap-2">
        <span className="text-xs font-semibold text-muted">#{sprint.order}</span>
        {!renaming && (
          <span className="min-w-0 flex-1 truncate text-sm font-medium text-content">
            {sprint.name}
          </span>
        )}
      </div>

      {renaming ? (
        <div className="mt-2 flex flex-col gap-2">
          <Input
            aria-label={`Renommer le sprint ${sprint.name}`}
            value={renameDraft}
            onChange={(e) => onRenameDraftChange(e.target.value)}
            disabled={vm.busy}
          />
          <div className="flex justify-end gap-2">
            <Button size="sm" variant="ghost" disabled={vm.busy} onClick={onCancelRename}>
              Annuler
            </Button>
            <Button
              size="sm"
              disabled={vm.busy || !renameDraft.trim() || renameDraft.trim() === sprint.name}
              onClick={() => void onSaveRename()}
            >
              Enregistrer
            </Button>
          </div>
        </div>
      ) : (
        <>
          <p className="mt-1 text-xs text-muted">
            {sprint.ticketCount} ticket{sprint.ticketCount > 1 ? "s" : ""}
          </p>

          {/* Compact ticket list + per-row removal (QA #86 fix): symmetric with
              "Ajouter tickets" below. */}
          {tickets.length > 0 && (
            <ul className="mt-2 flex flex-col gap-1">
              {tickets.map((t) => (
                <li key={t.ref} className="flex items-center gap-2 text-sm">
                  <code className="shrink-0 rounded bg-raised px-1.5 py-0.5 font-mono text-xs text-content">
                    {t.ref}
                  </code>
                  <span className="min-w-0 flex-1 truncate text-content">{t.title}</span>
                  <Button
                    size="sm"
                    variant="ghost"
                    aria-label={`Retirer ${t.ref} du sprint ${sprint.name}`}
                    disabled={vm.busy}
                    onClick={() => void vm.assignSprint(t.ref, null)}
                  >
                    Retirer du sprint
                  </Button>
                </li>
              ))}
            </ul>
          )}

          <div className="mt-2 flex flex-wrap items-center gap-2">
            <Button size="sm" variant="ghost" onClick={onViewTickets}>
              Voir tickets
            </Button>
            <Button size="sm" variant="ghost" onClick={onAddTickets}>
              Ajouter tickets
            </Button>
            <Button
              size="sm"
              variant="ghost"
              aria-label={`Renommer ${sprint.name}`}
              disabled={vm.busy}
              onClick={onStartRename}
            >
              Renommer
            </Button>
            <Button
              size="sm"
              variant="ghost"
              aria-label={`Monter ${sprint.name}`}
              disabled={vm.busy || index === 0}
              onClick={() => void vm.moveSprint(sprint.id, "up")}
            >
              Monter
            </Button>
            <Button
              size="sm"
              variant="ghost"
              aria-label={`Descendre ${sprint.name}`}
              disabled={vm.busy || index === lastIndex}
              onClick={() => void vm.moveSprint(sprint.id, "down")}
            >
              Descendre
            </Button>
            <Button
              size="sm"
              variant="ghost"
              aria-label={`Supprimer ${sprint.name}`}
              disabled={vm.busy}
              className="text-danger hover:text-danger"
              onClick={onRequestDelete}
            >
              Supprimer
            </Button>
          </div>
        </>
      )}
    </li>
  );
}
