import { createFileRoute, Link } from "@tanstack/react-router";
import { useEffect, useState } from "react";
import { useServerFn } from "@tanstack/react-start";
import { ArrowLeft, Camera, Loader2, Plus, ShieldCheck, Trash2, Upload } from "lucide-react";
import {
  adminListPrompts,
  bulkImportPrompts,
  claimFirstAdmin,
  createPrompt,
  deletePrompt,
  getMyRoles,
  updatePrompt,
  type PromptRow,
} from "@/lib/prompts.functions";
import { toast } from "sonner";

export const Route = createFileRoute("/_authenticated/admin/prompts")({
  head: () => ({ meta: [{ title: "Admin · Prompt Library" }] }),
  component: AdminPromptsPage,
});

const AI_TOOLS = ["Any", "ChatGPT", "Midjourney", "Flux", "Ideogram"];

interface DraftPrompt {
  title: string;
  prompt_text: string;
  category: string;
  emotion_tags: string;
  personality_tags: string;
  style_tags: string;
  ai_tool: string;
  is_active: boolean;
}

const EMPTY: DraftPrompt = {
  title: "", prompt_text: "", category: "", emotion_tags: "", personality_tags: "", style_tags: "", ai_tool: "Any", is_active: true,
};

function splitTags(s: string): string[] {
  return s.split(",").map((t) => t.trim()).filter(Boolean);
}

function AdminPromptsPage() {
  const rolesFn = useServerFn(getMyRoles);
  const claimFn = useServerFn(claimFirstAdmin);
  const listFn = useServerFn(adminListPrompts);
  const createFn = useServerFn(createPrompt);
  const updateFn = useServerFn(updatePrompt);
  const deleteFn = useServerFn(deletePrompt);
  const bulkFn = useServerFn(bulkImportPrompts);

  const [isAdmin, setIsAdmin] = useState<boolean | null>(null);
  const [rows, setRows] = useState<PromptRow[] | null>(null);
  const [draft, setDraft] = useState<DraftPrompt>(EMPTY);
  const [bulkText, setBulkText] = useState("");
  const [busy, setBusy] = useState(false);

  async function init() {
    try {
      const r = await rolesFn();
      setIsAdmin(r.isAdmin);
      if (r.isAdmin) await refresh();
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "Failed");
    }
  }
  async function refresh() {
    try { setRows(await listFn()); } catch (e) { toast.error(e instanceof Error ? e.message : "Failed"); }
  }

  useEffect(() => { void init(); /* eslint-disable-next-line */ }, []);

  async function handleClaim() {
    try {
      const r = await claimFn();
      if (r.claimed) { toast.success("You're the admin now."); setIsAdmin(true); await refresh(); }
      else toast.error("An admin already exists. Ask them to grant you access.");
    } catch (e) { toast.error(e instanceof Error ? e.message : "Failed"); }
  }

  async function handleCreate() {
    if (!draft.title.trim() || !draft.prompt_text.trim()) { toast.error("Title and prompt text are required"); return; }
    setBusy(true);
    try {
      await createFn({ data: {
        title: draft.title, prompt_text: draft.prompt_text,
        category: draft.category || null,
        emotion_tags: splitTags(draft.emotion_tags),
        personality_tags: splitTags(draft.personality_tags),
        style_tags: splitTags(draft.style_tags),
        ai_tool: draft.ai_tool, is_active: draft.is_active,
      }});
      toast.success("Prompt added");
      setDraft(EMPTY);
      await refresh();
    } catch (e) { toast.error(e instanceof Error ? e.message : "Failed"); }
    finally { setBusy(false); }
  }

  async function handleBulk() {
    setBusy(true);
    try {
      const parsed = parseBulk(bulkText);
      if (parsed.length === 0) throw new Error("No valid prompts found");
      const r = await bulkFn({ data: { prompts: parsed } });
      toast.success(`Imported ${r.inserted} prompts`);
      setBulkText("");
      await refresh();
    } catch (e) { toast.error(e instanceof Error ? e.message : "Import failed"); }
    finally { setBusy(false); }
  }

  async function toggleActive(p: PromptRow) {
    try { await updateFn({ data: { id: p.id, patch: { is_active: !p.is_active } } }); await refresh(); }
    catch (e) { toast.error(e instanceof Error ? e.message : "Failed"); }
  }

  async function remove(p: PromptRow) {
    if (!confirm(`Delete "${p.title}"?`)) return;
    try { await deleteFn({ data: { id: p.id } }); toast.success("Deleted"); await refresh(); }
    catch (e) { toast.error(e instanceof Error ? e.message : "Failed"); }
  }

  if (isAdmin === null) {
    return <div className="min-h-screen grid place-content-center text-muted-foreground"><Loader2 className="h-6 w-6 animate-spin" /></div>;
  }

  if (!isAdmin) {
    return (
      <div className="min-h-screen bg-background grid place-content-center px-6">
        <div className="max-w-md w-full rounded-2xl border border-border bg-card p-8 text-center">
          <ShieldCheck className="h-10 w-10 text-gold mx-auto mb-4" />
          <h1 className="font-display text-2xl mb-2">Admin access required</h1>
          <p className="text-sm text-muted-foreground mb-6">
            If you're setting up the prompt library for the first time, claim admin below. Otherwise, ask an existing admin to grant you the role.
          </p>
          <button onClick={handleClaim} className="rounded-full bg-primary px-5 py-2.5 text-sm font-medium text-primary-foreground hover:opacity-90">
            Claim admin (first user only)
          </button>
          <div className="mt-6"><Link to="/" className="text-xs text-muted-foreground hover:text-foreground">← Home</Link></div>
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-background">
      <header className="border-b border-border sticky top-0 z-30 bg-background/80 backdrop-blur">
        <div className="mx-auto max-w-7xl px-6 h-16 flex items-center justify-between">
          <Link to="/" className="flex items-center gap-2">
            <div className="h-8 w-8 rounded-full bg-gradient-gold flex items-center justify-center"><Camera className="h-4 w-4 text-primary" /></div>
            <span className="font-display text-lg font-semibold">Admin · Prompts</span>
          </Link>
          <div className="flex items-center gap-4 text-sm text-muted-foreground">
            <Link to="/admin/analytics" className="hover:text-foreground inline-flex items-center gap-1.5">
              Analytics
            </Link>
            <Link to="/prompts" className="hover:text-foreground inline-flex items-center gap-1.5">
              <ArrowLeft className="h-4 w-4" /> Public library
            </Link>
          </div>
        </div>
      </header>

      <main className="mx-auto max-w-7xl px-6 py-10 grid lg:grid-cols-[1fr_1.4fr] gap-8">
        {/* LEFT: add + bulk import */}
        <div className="space-y-6">
          <section className="rounded-2xl border border-border bg-card p-6">
            <h2 className="font-display text-xl mb-4 flex items-center gap-2"><Plus className="h-5 w-5 text-gold" /> Add a prompt</h2>
            <div className="space-y-3">
              <Input label="Title" value={draft.title} onChange={(v) => setDraft({ ...draft, title: v })} />
              <Textarea label="Prompt text" value={draft.prompt_text} onChange={(v) => setDraft({ ...draft, prompt_text: v })} rows={5} />
              <div className="grid grid-cols-2 gap-3">
                <Input label="Category" value={draft.category} onChange={(v) => setDraft({ ...draft, category: v })} placeholder="Engagement" />
                <Select label="AI tool" value={draft.ai_tool} onChange={(v) => setDraft({ ...draft, ai_tool: v })} options={AI_TOOLS} />
              </div>
              <Input label="Emotion tags (comma-separated)" value={draft.emotion_tags} onChange={(v) => setDraft({ ...draft, emotion_tags: v })} placeholder="Romance, Joy" />
              <Input label="Personality tags" value={draft.personality_tags} onChange={(v) => setDraft({ ...draft, personality_tags: v })} placeholder="Elegant, Bold" />
              <Input label="Style tags" value={draft.style_tags} onChange={(v) => setDraft({ ...draft, style_tags: v })} placeholder="Luxury Editorial" />
              <label className="flex items-center gap-2 text-sm">
                <input type="checkbox" checked={draft.is_active} onChange={(e) => setDraft({ ...draft, is_active: e.target.checked })} />
                Active (visible in public library)
              </label>
              <button disabled={busy} onClick={handleCreate} className="w-full rounded-lg bg-primary px-4 py-2.5 text-sm font-medium text-primary-foreground hover:opacity-90 disabled:opacity-50">
                {busy ? "Saving…" : "Add prompt"}
              </button>
            </div>
          </section>

          <section className="rounded-2xl border border-border bg-card p-6">
            <h2 className="font-display text-xl mb-2 flex items-center gap-2"><Upload className="h-5 w-5 text-gold" /> Bulk import</h2>
            <p className="text-xs text-muted-foreground mb-3">
              Paste <strong>JSON array</strong> or <strong>CSV</strong>. JSON keys: <code>title, prompt_text, category, emotion_tags[], personality_tags[], style_tags[], ai_tool, is_active</code>.
              CSV headers same names; tag columns use <code>|</code> as separator.
            </p>
            <textarea
              value={bulkText}
              onChange={(e) => setBulkText(e.target.value)}
              rows={10}
              placeholder={`[{"title":"...","prompt_text":"...","category":"Engagement","ai_tool":"Midjourney","emotion_tags":["Romance"],"style_tags":["Cinematic"]}]`}
              className="w-full rounded-lg border border-input bg-background p-3 text-xs font-mono focus:outline-none focus:ring-2 focus:ring-ring/40"
            />
            <button disabled={busy || !bulkText.trim()} onClick={handleBulk} className="mt-3 w-full rounded-lg bg-primary px-4 py-2.5 text-sm font-medium text-primary-foreground hover:opacity-90 disabled:opacity-50">
              {busy ? "Importing…" : "Import"}
            </button>
          </section>
        </div>

        {/* RIGHT: list */}
        <section className="rounded-2xl border border-border bg-card p-6">
          <div className="flex items-center justify-between mb-4">
            <h2 className="font-display text-xl">All prompts {rows ? `(${rows.length})` : ""}</h2>
            <button onClick={refresh} className="text-xs uppercase tracking-[0.2em] text-muted-foreground hover:text-foreground">Refresh</button>
          </div>
          {!rows ? (
            <div className="py-12 text-center"><Loader2 className="h-5 w-5 animate-spin mx-auto text-muted-foreground" /></div>
          ) : rows.length === 0 ? (
            <p className="py-12 text-center text-sm text-muted-foreground">No prompts yet. Add your first on the left.</p>
          ) : (
            <ul className="space-y-3 max-h-[70vh] overflow-y-auto pr-2">
              {rows.map((p) => (
                <li key={p.id} className={`rounded-xl border p-4 ${p.is_active ? "border-border bg-background" : "border-dashed border-muted-foreground/30 bg-muted/30 opacity-70"}`}>
                  <div className="flex items-start justify-between gap-3 mb-1">
                    <h3 className="font-medium">{p.title}</h3>
                    <div className="flex items-center gap-2 shrink-0">
                      <button onClick={() => toggleActive(p)} className="text-[10px] uppercase tracking-[0.15em] text-muted-foreground hover:text-foreground">
                        {p.is_active ? "Hide" : "Show"}
                      </button>
                      <button onClick={() => remove(p)} className="text-destructive hover:opacity-80"><Trash2 className="h-4 w-4" /></button>
                    </div>
                  </div>
                  <p className="text-xs text-muted-foreground line-clamp-2 mb-2">{p.prompt_text}</p>
                  <div className="flex flex-wrap gap-1">
                    {p.category && <Pill>{p.category}</Pill>}
                    <Pill>{p.ai_tool}</Pill>
                    {p.emotion_tags.map((t) => <Pill key={`e${t}`}>{t}</Pill>)}
                    {p.style_tags.map((t) => <Pill key={`s${t}`}>{t}</Pill>)}
                  </div>
                </li>
              ))}
            </ul>
          )}
        </section>
      </main>
    </div>
  );
}

interface BulkPrompt {
  title: string;
  prompt_text: string;
  category: string | null;
  emotion_tags: string[];
  personality_tags: string[];
  style_tags: string[];
  ai_tool: string;
  is_active: boolean;
}

function parseBulk(text: string): BulkPrompt[] {
  const trimmed = text.trim();
  if (!trimmed) return [];
  // JSON array
  if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
    const raw = JSON.parse(trimmed);
    const arr: unknown[] = Array.isArray(raw) ? raw : [raw];
    return arr.map((x) => {
      const o = x as Record<string, unknown>;
      return {
        title: String(o.title ?? ""),
        prompt_text: String(o.prompt_text ?? o.prompt ?? ""),
        category: (o.category as string) || null,
        emotion_tags: Array.isArray(o.emotion_tags) ? (o.emotion_tags as string[]) : [],
        personality_tags: Array.isArray(o.personality_tags) ? (o.personality_tags as string[]) : [],
        style_tags: Array.isArray(o.style_tags) ? (o.style_tags as string[]) : [],
        ai_tool: (o.ai_tool as string) || "Any",
        is_active: o.is_active === false ? false : true,
      };
    }).filter((p) => p.title && p.prompt_text);
  }
  // CSV
  const lines = trimmed.split(/\r?\n/).filter(Boolean);
  const headers = parseCsvRow(lines[0]).map((h) => h.toLowerCase());
  return lines.slice(1).map((line) => {
    const cells = parseCsvRow(line);
    const get = (k: string) => cells[headers.indexOf(k)] ?? "";
    return {
      title: get("title"),
      prompt_text: get("prompt_text") || get("prompt"),
      category: get("category") || null,
      emotion_tags: get("emotion_tags").split("|").map((s) => s.trim()).filter(Boolean),
      personality_tags: get("personality_tags").split("|").map((s) => s.trim()).filter(Boolean),
      style_tags: get("style_tags").split("|").map((s) => s.trim()).filter(Boolean),
      ai_tool: get("ai_tool") || "Any",
      is_active: get("is_active").toLowerCase() !== "false",
    };
  }).filter((p) => p.title && p.prompt_text);
}

function parseCsvRow(line: string): string[] {
  const out: string[] = [];
  let cur = ""; let inQ = false;
  for (let i = 0; i < line.length; i++) {
    const c = line[i];
    if (inQ) {
      if (c === '"' && line[i + 1] === '"') { cur += '"'; i++; }
      else if (c === '"') inQ = false;
      else cur += c;
    } else {
      if (c === ',') { out.push(cur); cur = ""; }
      else if (c === '"') inQ = true;
      else cur += c;
    }
  }
  out.push(cur);
  return out.map((s) => s.trim());
}

function Input({ label, value, onChange, placeholder }: { label: string; value: string; onChange: (v: string) => void; placeholder?: string }) {
  return (
    <label className="block">
      <span className="block text-[10px] uppercase tracking-[0.2em] text-muted-foreground mb-1">{label}</span>
      <input value={value} onChange={(e) => onChange(e.target.value)} placeholder={placeholder}
        className="w-full rounded-lg border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring/40" />
    </label>
  );
}
function Textarea({ label, value, onChange, rows = 4 }: { label: string; value: string; onChange: (v: string) => void; rows?: number }) {
  return (
    <label className="block">
      <span className="block text-[10px] uppercase tracking-[0.2em] text-muted-foreground mb-1">{label}</span>
      <textarea value={value} onChange={(e) => onChange(e.target.value)} rows={rows}
        className="w-full rounded-lg border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring/40" />
    </label>
  );
}
function Select({ label, value, onChange, options }: { label: string; value: string; onChange: (v: string) => void; options: string[] }) {
  return (
    <label className="block">
      <span className="block text-[10px] uppercase tracking-[0.2em] text-muted-foreground mb-1">{label}</span>
      <select value={value} onChange={(e) => onChange(e.target.value)}
        className="w-full rounded-lg border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring/40">
        {options.map((o) => <option key={o} value={o}>{o}</option>)}
      </select>
    </label>
  );
}
function Pill({ children }: { children: React.ReactNode }) {
  return <span className="text-[10px] uppercase tracking-[0.15em] px-2 py-0.5 rounded-full border border-border text-muted-foreground">{children}</span>;
}
