"use client";

import Link from "next/link";
import { useRouter } from "next/navigation";
import { useRef, useState, useTransition } from "react";
import { Button, Card } from "@/components/ui";
import { deleteCategoriesAction, importCategoriesAction, moveCategoryAction, setCategoryLibrariesAction, sortCategoriesAction } from "@/lib/actions/categories";
import { CategoryDialog, type CategoryDraft, type Language } from "./category-dialog";

export interface TreeNode { id: string; name: string; code: string; selectable: boolean; labels: Record<string, string>; children: TreeNode[] }
interface Group { id: string; name: string; code: string; labels: Record<string, string>; scopes: string[] }

/** ShowOff category view: the categories of one group (Categories tab) and which libraries use it (Assigned To tab). */
export function CategoryTree({ siteId, base, group, tree, libraries, languages, initialTab }: { siteId: string; base: string; group: Group; tree: TreeNode[]; libraries: { key: string; label: string }[]; languages: Language[]; initialTab: "categories" | "assigned" }) {
  const router = useRouter();
  const [tab, setTab] = useState(initialTab);
  const [draft, setDraft] = useState<CategoryDraft | null>(null);
  const [dialogTitle, setDialogTitle] = useState("Add Category");
  const [selected, setSelected] = useState<Set<string>>(new Set());
  const [armed, setArmed] = useState<string | null>(null);
  const [menu, setMenu] = useState(false);
  const [importOpen, setImportOpen] = useState(false);
  const [importText, setImportText] = useState("");
  const [importTarget, setImportTarget] = useState(group.id);
  const [scopes, setScopes] = useState(new Set(group.scopes));
  const [msg, setMsg] = useState<{ ok: boolean; text: string } | null>(null);
  const [pending, start] = useTransition();
  const importDlg = useRef<HTMLDialogElement>(null);
  const def = languages.find((l) => l.isDefault)?.locale ?? "en-GB";

  const run = (fn: () => Promise<{ ok: boolean; message?: string; error?: string }>, after?: () => void) => start(async () => {
    const r = await fn();
    setMsg({ ok: r.ok, text: (r.ok ? r.message : r.error) ?? (r.ok ? "Done" : "Something went wrong") });
    if (r.ok) { after?.(); router.refresh(); }
  });
  const open = (title: string, d: CategoryDraft) => { setDialogTitle(title); setDraft(d); };
  const editNode = (n: TreeNode) => open("Edit Category", { id: n.id, parentId: null, isGroup: false, code: n.code, labels: { ...n.labels, [def]: n.name }, selectable: n.selectable });
  const editGroup = (title: string) => open(title, { id: group.id, isGroup: true, code: group.code, labels: { ...group.labels, [def]: group.name }, selectable: true });
  const addTo = (parentId: string) => open("Add Category", { parentId, isGroup: false, code: "", labels: {}, selectable: true });
  const toggle = (id: string) => setSelected((s) => { const n = new Set(s); if (n.has(id)) n.delete(id); else n.add(id); return n; });
  const flat = (nodes: TreeNode[], depth = 0): { n: TreeNode; depth: number }[] => nodes.flatMap((n) => [{ n, depth }, ...flat(n.children, depth + 1)]);
  const parents = [{ id: group.id, label: group.name }, ...flat(tree).map(({ n, depth }) => ({ id: n.id, label: `${"— ".repeat(depth + 1)}${n.name}` }))];

  const renderNodes = (nodes: TreeNode[]) => (
    <ul className="space-y-2">
      {nodes.map((n, i) => (
        <li key={n.id}>
          <div className="flex flex-wrap items-center gap-2 rounded-md border border-border bg-card px-3 py-2">
            <input type="checkbox" aria-label={`Select ${n.name}`} checked={selected.has(n.id)} onChange={() => toggle(n.id)} />
            <span className="min-w-0 flex-1 text-sm">{n.name}{n.code ? <span className="ml-1 text-xs text-muted-foreground">({n.code})</span> : null}{!n.selectable ? <span className="ml-2 rounded bg-muted px-1.5 py-0.5 text-xs text-muted-foreground">heading only</span> : null}</span>
            <span className="flex flex-wrap gap-1">
              <Button variant="secondary" disabled={pending || i === 0} onClick={() => run(() => moveCategoryAction(siteId, n.id, "up"))} aria-label={`Move ${n.name} up`}>Up</Button>
              <Button variant="secondary" disabled={pending || i === nodes.length - 1} onClick={() => run(() => moveCategoryAction(siteId, n.id, "down"))} aria-label={`Move ${n.name} down`}>Down</Button>
              <Button variant="secondary" onClick={() => addTo(n.id)} aria-label={`Add child category to ${n.name}`}>Add Child Category</Button>
              <Button variant="secondary" onClick={() => editNode(n)} aria-label={`Edit ${n.name}`}>Edit</Button>
              {armed === n.id ? (
                <><Button variant="danger" disabled={pending} onClick={() => run(() => deleteCategoriesAction(siteId, [n.id]), () => setArmed(null))}>Confirm delete</Button><Button variant="secondary" onClick={() => setArmed(null)}>Cancel</Button></>
              ) : <Button variant="secondary" onClick={() => setArmed(n.id)} aria-label={`Delete ${n.name}`}>Delete</Button>}
            </span>
          </div>
          {n.children.length ? <div className="ml-6 mt-2 border-l border-border pl-3">{renderNodes(n.children)}</div> : null}
        </li>
      ))}
    </ul>
  );

  function openImport(id: string) { setImportTarget(id); setImportOpen(true); queueMicrotask(() => importDlg.current?.showModal()); }

  return (
    <>
      <nav aria-label="Breadcrumb" className="mb-2 text-sm"><Link href={base} className="text-primary underline">Categories</Link></nav>
      <div className="mb-6 flex flex-wrap items-end justify-between gap-3">
        <div><h1 className="text-xl font-semibold tracking-tight">{group.name}{group.code ? <span className="ml-2 text-base font-normal text-muted-foreground">({group.code})</span> : null}</h1></div>
        <div className="relative flex gap-2">
          <Button variant="secondary" onClick={() => addTo(group.id)}>Add Category</Button>
          <Button variant="secondary" aria-haspopup="menu" aria-expanded={menu} onClick={() => setMenu((m) => !m)}>More</Button>
          {menu ? (
            <div role="menu" className="absolute right-0 top-11 z-10 w-44 rounded-md border border-border bg-card p-1 shadow-md" onKeyDown={(e) => { if (e.key === "Escape") setMenu(false); }}>
              <MenuItem onPick={() => { setMenu(false); editGroup("Edit Category"); }}>Edit Category</MenuItem>
              <MenuItem onPick={() => { setMenu(false); run(() => sortCategoriesAction(siteId, group.id, "az")); }}>Order by A-Z</MenuItem>
              <MenuItem onPick={() => { setMenu(false); run(() => sortCategoriesAction(siteId, group.id, "za")); }}>Order by Z-A</MenuItem>
              <MenuItem onPick={() => { setMenu(false); editGroup("Translate"); }}>Translate</MenuItem>
              <MenuItem onPick={() => { setMenu(false); openImport(group.id); }}>Import</MenuItem>
            </div>
          ) : null}
        </div>
      </div>
      <p role="status" aria-live="polite" className={msg ? (msg.ok ? "mb-3 text-sm text-success" : "mb-3 text-sm text-danger") : "sr-only"}>{msg?.text}</p>

      <div role="tablist" aria-label="Category sections" className="mb-4 flex gap-1 border-b border-border">
        {([["categories", "Categories"], ["assigned", "Assigned To"]] as const).map(([k, label]) => (
          <button key={k} role="tab" type="button" id={`ct-${k}`} aria-selected={tab === k} aria-controls="ct-panel" onClick={() => setTab(k)} className={`-mb-px border-b-2 px-3 py-2 text-sm ${tab === k ? "border-primary font-medium" : "border-transparent text-muted-foreground hover:text-foreground"}`}>{label}</button>
        ))}
      </div>
      <div role="tabpanel" id="ct-panel" aria-labelledby={`ct-${tab}`}>
        {tab === "categories" ? (
          <Card className="space-y-3 p-4">
            {selected.size > 0 ? (
              <div className="flex items-center gap-3 rounded-md bg-muted px-3 py-2 text-sm">
                <span>{selected.size} selected</span>
                <Button variant="danger" disabled={pending} onClick={() => run(() => deleteCategoriesAction(siteId, [...selected]), () => setSelected(new Set()))}>Delete selected</Button>
                <Button variant="secondary" onClick={() => setSelected(new Set())}>Clear</Button>
              </div>
            ) : null}
            {tree.length === 0 ? <p className="py-6 text-center text-sm text-muted-foreground">No categories in this group yet. Use Add Category or Import.</p> : renderNodes(tree)}
          </Card>
        ) : (
          <Card className="space-y-3 p-4">
            <p className="text-sm font-medium">Select which libraries this category group applies to:</p>
            <ul className="space-y-2">
              {libraries.map((l) => (
                <li key={l.key}><label className="flex items-center gap-2 text-sm"><input type="checkbox" checked={scopes.has(l.key)} onChange={() => setScopes((s) => { const n = new Set(s); if (n.has(l.key)) n.delete(l.key); else n.add(l.key); return n; })} />{l.label}</label></li>
              ))}
            </ul>
            <Button disabled={pending} onClick={() => run(() => setCategoryLibrariesAction(siteId, group.id, [...scopes]))}>{pending ? "Saving…" : "Save"}</Button>
          </Card>
        )}
      </div>

      <CategoryDialog siteId={siteId} draft={draft} languages={languages} title={dialogTitle} onClose={() => setDraft(null)} onSaved={() => { setDraft(null); setMsg({ ok: true, text: "Category saved" }); router.refresh(); }} />
      <dialog ref={importDlg} onClose={() => setImportOpen(false)} aria-labelledby="imp-title" className="m-auto w-[min(32rem,92vw)] rounded-lg border border-border bg-card p-5 text-foreground backdrop:bg-black/40">
        {importOpen ? (
          <form className="space-y-4" onSubmit={(e) => { e.preventDefault(); run(() => importCategoriesAction(siteId, importTarget, importText), () => { setImportText(""); importDlg.current?.close(); }); }}>
            <h2 id="imp-title" className="text-base font-semibold">Import categories</h2>
            <p className="text-xs text-muted-foreground">One category per line, either a label or a code and a label separated by a comma (for example <code>BE,Business Innovation Expo</code>). Names already in the chosen place are skipped.</p>
            <label htmlFor="imp-parent" className="block text-sm font-medium">Add to</label>
            <select id="imp-parent" className="w-full rounded-md border border-border bg-card px-3 py-2 text-sm" value={importTarget} onChange={(e) => setImportTarget(e.target.value)}>{parents.map((p) => <option key={p.id} value={p.id}>{p.label}</option>)}</select>
            <label htmlFor="imp-text" className="block text-sm font-medium">Categories</label>
            <textarea id="imp-text" rows={8} className="w-full rounded-md border border-border bg-card px-3 py-2 font-mono text-sm" value={importText} onChange={(e) => setImportText(e.target.value)} />
            <div className="flex justify-end gap-2"><Button variant="secondary" onClick={() => importDlg.current?.close()}>Cancel</Button><Button type="submit" disabled={pending || !importText.trim()}>{pending ? "Importing…" : "Import"}</Button></div>
          </form>
        ) : null}
      </dialog>
    </>
  );
}

function MenuItem({ onPick, children }: { onPick: () => void; children: React.ReactNode }) {
  return <button role="menuitem" type="button" className="block w-full rounded px-3 py-2 text-left text-sm hover:bg-muted" onClick={onPick}>{children}</button>;
}
