import { useEffect, useMemo, useState } from 'react';
import {
  Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { useI18n } from '@/lib/i18n';
import { writeUiPref } from '@/lib/uiPref';
import { ADIFFields, ADIFExtraFields } from '@/../wailsjs/go/main/App';
import { adif } from '@/../wailsjs/go/models';

type FieldDef = adif.FieldDef;
const PREF_KEY = 'opslog.exportFields';

// One category card with its checkboxes + All/None. Defined at MODULE scope (not
// inside ExportFieldsDialog) so its component identity is stable across renders —
// an inner component is re-created every render, remounting the whole subtree and
// making the All/None buttons and checkboxes feel dead.
function GroupCard({ title, tags, warn, sel, allLabel, noneLabel, onAll, onNone, onToggle }: {
  title: string; tags: string[]; warn?: boolean; sel: Set<string>;
  allLabel: string; noneLabel: string;
  onAll: (tags: string[]) => void; onNone: (tags: string[]) => void; onToggle: (name: string, on: boolean) => void;
}) {
  return (
    <div className={`rounded-md border p-2 ${warn ? 'border-warning-border/50 bg-warning-muted/20' : 'border-border/60'}`}>
      <div className="flex items-center justify-between mb-1 gap-2">
        <span className={`text-[11px] font-semibold uppercase tracking-wide ${warn ? 'text-warning-muted-foreground' : 'text-muted-foreground'}`}>{title}</span>
        <span className="flex gap-1.5 shrink-0">
          <button type="button" className="text-[10px] text-primary hover:underline" onClick={() => onAll(tags)}>{allLabel}</button>
          <button type="button" className="text-[10px] text-muted-foreground hover:underline" onClick={() => onNone(tags)}>{noneLabel}</button>
        </span>
      </div>
      {tags.map((name) => (
        <label key={name} className="flex items-center gap-1.5 text-[11px] cursor-pointer py-0.5">
          <Checkbox checked={sel.has(name)} onCheckedChange={(c) => onToggle(name, !!c)} />
          <span className="font-mono break-all">{name}</span>
        </label>
      ))}
    </div>
  );
}

// ExportFieldsDialog lets the operator pick exactly which ADIF fields an export
// writes. Two groups: the official ADIF 3.1.7 dictionary (grouped by category)
// and the OpsLog / non-standard tags actually present in the log's extras. The
// chosen set is returned to the parent (which runs the selected/global export)
// and persisted so it's the default next time.
export function ExportFieldsDialog({ open, count, onExport, onClose }: {
  open: boolean;
  count: number;              // how many QSOs the pending export covers
  onExport: (fields: string[]) => void;
  onClose: () => void;
}) {
  const { t } = useI18n();
  const [official, setOfficial] = useState<FieldDef[]>([]);
  const [extras, setExtras] = useState<string[]>([]);
  const [sel, setSel] = useState<Set<string>>(new Set());

  const defaultSet = (flds: FieldDef[]) =>
    new Set(flds.filter((d) => d.promoted && !d.deprecated).map((d) => d.name));

  useEffect(() => {
    if (!open) return;
    let cancelled = false;
    (async () => {
      const [f, e] = await Promise.all([ADIFFields(), ADIFExtraFields()]);
      if (cancelled) return;
      const flds = (f ?? []) as FieldDef[];
      setOfficial(flds);
      setExtras((e ?? []) as string[]);
      let saved: string[] | null = null;
      try { const raw = localStorage.getItem(PREF_KEY); if (raw) saved = JSON.parse(raw); } catch { /* ignore */ }
      setSel(saved && saved.length ? new Set(saved.map((x) => x.toUpperCase())) : defaultSet(flds));
    })().catch(() => {});
    return () => { cancelled = true; };
  }, [open]);

  // Official fields grouped by category (deprecated ones are import-only → hidden).
  const groups = useMemo(() => {
    const m = new Map<string, FieldDef[]>();
    for (const d of official) {
      if (d.deprecated) continue;
      const g = d.category || 'Misc';
      (m.get(g) ?? m.set(g, []).get(g)!).push(d);
    }
    return [...m.entries()];
  }, [official]);

  // Every tag the dialog can offer — the extras AND every group — so "select
  // all" means what it says rather than "all the official ones".
  const everyTag = useMemo(
    () => [...extras, ...groups.flatMap(([, list]) => list.map((d) => d.name))],
    [extras, groups],
  );

  const toggle = (name: string, on: boolean) =>
    setSel((s) => { const n = new Set(s); if (on) n.add(name); else n.delete(name); return n; });
  const setMany = (names: string[], on: boolean) =>
    setSel((s) => { const n = new Set(s); for (const x of names) { if (on) n.add(x); else n.delete(x); } return n; });

  const doExport = () => {
    const fields = [...sel];
    writeUiPref(PREF_KEY, JSON.stringify(fields));
    onExport(fields);
  };

  const allLabel = t('exf.all');
  const noneLabel = t('exf.none');
  const cardProps = {
    sel, allLabel, noneLabel,
    onAll: (tags: string[]) => setMany(tags, true),
    onNone: (tags: string[]) => setMany(tags, false),
    onToggle: toggle,
  };

  return (
    <Dialog open={open} onOpenChange={(o) => { if (!o) onClose(); }}>
      <DialogContent className="max-w-4xl">
        <DialogHeader>
          <DialogTitle>{t('exf.title')}</DialogTitle>
          <DialogDescription>{t('exf.desc')}</DialogDescription>
        </DialogHeader>

        {/* Whole-dialog select/clear, next to the count they change. Per-group
            links alone meant clearing the selection was one click PER GROUP —
            a dozen of them to get to "just the handful I want". */}
        <div className="flex items-center gap-2 px-1 text-[11px] text-muted-foreground">
          <span>{t('exf.chosen', { n: sel.size })}</span>
          <span className="ml-auto inline-flex items-center gap-1">
            <Button variant="ghost" size="sm" className="h-6 text-[11px]"
              onClick={() => setSel(new Set(everyTag))}>
              {t('exf.selectAll')}
            </Button>
            <Button variant="ghost" size="sm" className="h-6 text-[11px]"
              disabled={sel.size === 0}
              onClick={() => setSel(new Set())}>
              {t('exf.selectNone')}
            </Button>
            <Button variant="ghost" size="sm" className="h-6 text-[11px]" onClick={() => setSel(defaultSet(official))}>
              {t('exf.defaults')}
            </Button>
          </span>
        </div>

        <div className="grid grid-cols-3 gap-3 max-h-[56vh] overflow-y-auto pr-1">
          {/* OpsLog / non-standard group first (most relevant to keep or drop). */}
          {extras.length > 0 && <GroupCard title={t('exf.opslogGroup')} tags={extras} warn {...cardProps} />}
          {groups.map(([g, list]) => (
            <GroupCard key={g} title={g} tags={list.map((d) => d.name)} {...cardProps} />
          ))}
        </div>

        <DialogFooter>
          <Button variant="outline" onClick={onClose}>{t('exf.cancel')}</Button>
          <Button disabled={sel.size === 0} onClick={doExport}>{t('exf.export', { n: count })}</Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
