
import { useState } from 'react';
import { X } from 'lucide-react';
import type { Campaign, Homebrew, HomebrewKind } from '@/lib/schemas';
import { homebrewSchema } from '@/lib/schemas';
import { homebrewRepo } from '@/lib/db/repositories';
import { downloadJson, pickTextFile, safeFilename } from '@/lib/io/file';
import { useHomebrew } from './hooks';
import { HOMEBREW_FIELDS, HOMEBREW_KIND_LABEL } from './homebrew';
import { Page, PageHeader, EmptyState, RequireCampaign } from '@/components/ui/Page';
import { Button } from '@/components/ui/Button';
import { Input, Select } from '@/components/ui/Input';
import { useConfirm } from '@/components/ui/useConfirm';
import { useDebouncedCallback } from '@/lib/useDebouncedCallback';

const KINDS: HomebrewKind[] = ['monster', 'spell', 'item', 'feat', 'condition'];
const PACK_FORMAT = 'ttrpg-manager:homebrew-pack';

export function HomebrewPage() {
  return <RequireCampaign>{(c) => <HomebrewView campaign={c} />}</RequireCampaign>;
}

function HomebrewView({ campaign }: { campaign: Campaign }) {
  const entries = useHomebrew(campaign.id);
  const [kind, setKind] = useState<HomebrewKind>('monster');
  const [msg, setMsg] = useState<string | null>(null);

  const exportPack = () => {
    downloadJson(`${safeFilename(campaign.name)}.homebrew.json`, { format: PACK_FORMAT, version: 1, entries });
    setMsg(`Exported ${entries.length} entr${entries.length === 1 ? 'y' : 'ies'}.`);
  };

  const importPack = async () => {
    setMsg(null);
    const text = await pickTextFile();
    if (!text) return;
    try {
      const raw = JSON.parse(text) as { entries?: unknown };
      const list = Array.isArray(raw.entries) ? raw.entries : Array.isArray(raw) ? (raw as unknown[]) : [];
      const valid = list.map((e) => homebrewSchema.safeParse(e)).filter((r) => r.success).map((r) => r.data);
      if (valid.length === 0) { setMsg('No valid homebrew entries in that file.'); return; }
      const n = await homebrewRepo.importMany(campaign.id, valid as Homebrew[]);
      setMsg(`Imported ${n} entr${n === 1 ? 'y' : 'ies'}.`);
    } catch {
      setMsg('That file is not a valid homebrew pack.');
    }
  };

  const byKind = (k: HomebrewKind) => entries.filter((e) => e.kind === k).sort((a, b) => a.name.localeCompare(b.name));

  return (
    <Page>
      <PageHeader
        title="Homebrew"
        subtitle={`${campaign.name} · custom content shows in the Compendium with an HB badge`}
        actions={
          <>
            <Button variant="ghost" onClick={importPack}>Import pack</Button>
            <Button variant="ghost" disabled={entries.length === 0} onClick={exportPack}>Export pack</Button>
          </>
        }
      />

      <div className="mb-4 flex items-center gap-2">
        <Select className="w-auto" value={kind} onChange={(e) => setKind(e.target.value as HomebrewKind)} aria-label="Homebrew kind">
          {KINDS.map((k) => <option key={k} value={k}>{HOMEBREW_KIND_LABEL[k]}</option>)}
        </Select>
        <Button variant="primary" onClick={() => homebrewRepo.create(campaign.id, campaign.system, kind, `New ${HOMEBREW_KIND_LABEL[kind]}`)}>
          + New {HOMEBREW_KIND_LABEL[kind].toLowerCase()}
        </Button>
        {msg && <span className="text-sm text-success" aria-live="polite">{msg}</span>}
      </div>

      {entries.length === 0 ? (
        <EmptyState title="No homebrew yet" hint="Create custom monsters, spells, items, feats, and conditions — or import a pack." />
      ) : (
        <div className="space-y-6">
          {KINDS.map((k) => {
            const list = byKind(k);
            if (list.length === 0) return null;
            return (
              <section key={k}>
                <h2 className="mb-2 smallcaps">{HOMEBREW_KIND_LABEL[k]}s</h2>
                <div className="grid gap-3 md:grid-cols-2">
                  {list.map((hb) => <HomebrewCard key={hb.id} hb={hb} />)}
                </div>
              </section>
            );
          })}
        </div>
      )}
    </Page>
  );
}

function HomebrewCard({ hb }: { hb: Homebrew }) {
  const [h, setH] = useState(hb);
  const { confirm, confirmElement } = useConfirm();
  // Save the full snapshot (not partial patches) so editing several fields
  // quickly doesn't drop earlier edits under the debounce.
  const save = useDebouncedCallback((next: Homebrew) => void homebrewRepo.update(next.id, { name: next.name, fields: next.fields, description: next.description }), 350);
  const update = (patch: Partial<Homebrew>) => setH((p) => { const next = { ...p, ...patch }; save(next); return next; });
  const setField = (key: string, value: string | number) => update({ fields: { ...h.fields, [key]: value } });

  return (
    <div className="rounded-lg border border-line bg-panel p-4">
      <div className="flex items-center gap-2">
        <Input className="font-display font-semibold" value={h.name} onChange={(e) => update({ name: e.target.value })} aria-label="Homebrew name" />
        <Button size="icon" variant="ghost" className="text-danger" onClick={async () => { if (await confirm({ title: 'Delete entry?', message: <>Delete <strong className="text-ink">{h.name || 'this entry'}</strong>? This can’t be undone.</> })) void homebrewRepo.remove(hb.id); }} aria-label={`Delete ${h.name}`}><X size={14} aria-hidden /></Button>
      </div>
      {confirmElement}
      {HOMEBREW_FIELDS[hb.kind].length > 0 && (
        <div className="mt-2 grid grid-cols-2 gap-2">
          {HOMEBREW_FIELDS[hb.kind].map((f) => (
            <label key={f.key} className="text-xs text-muted">
              {f.label}
              <Input
                type={f.type === 'number' ? 'number' : 'text'}
                value={String(h.fields[f.key] ?? '')}
                onChange={(e) => setField(f.key, f.type === 'number' ? Number(e.target.value) || 0 : e.target.value)}
                aria-label={f.label}
              />
            </label>
          ))}
        </div>
      )}
      <textarea
        value={h.description}
        onChange={(e) => update({ description: e.target.value })}
        placeholder="Description, abilities, rules text…"
        className="mt-2 min-h-20 w-full resize-y rounded-md border border-line bg-surface px-3 py-2 text-sm text-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/60"
      />
    </div>
  );
}
