import { useEffect, useState } from 'react';
import { Upload, FolderOpen, Loader2, ChevronsUpDown } from 'lucide-react';
import {
  GetWebPublishConfig, SaveWebPublishConfig, WebPublishColumns,
  TestWebPublishFTP, PublishLogNow, GetWebPublishStatus, PickBackupFolder,
} from '../../wailsjs/go/main/App';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Checkbox } from '@/components/ui/checkbox';
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@/components/ui/select';
import {
  DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuCheckboxItem,
} from '@/components/ui/dropdown-menu';
import { useI18n } from '@/lib/i18n';
import { cn } from '@/lib/utils';

type Cfg = {
  enabled: boolean; format: string; folder: string; file_name: string; title: string;
  count: number; interval_min: number; columns: string[];
  ftp_enabled: boolean; ftp_host: string; ftp_port: number; ftp_user: string;
  ftp_password: string; ftp_tls: boolean; ftp_folder: string; ftp_file_name: string;
};
type Col = { key: string; header: string; group: string };

export function WebPublishPanel() {
  const { t } = useI18n();
  const [cfg, setCfg] = useState<Cfg | null>(null);
  const [cols, setCols] = useState<Col[]>([]);
  // The catalogue is 123 fields, so the picker is a dropdown with a search box
  // rather than anything laid out on the page. Chosen columns stay visible above
  // it, in publication order: after picking eight out of a hundred the question
  // stops being 'what exists' and becomes 'what did I pick, and how will it print'.
  const [colSearch, setColSearch] = useState('');
  const [busy, setBusy] = useState<'' | 'test' | 'publish'>('');
  const [msg, setMsg] = useState('');
  const [err, setErr] = useState('');
  // Raw text for the two numeric boxes: bound straight to the number they could
  // not be cleared, the same trap as the Recent-QSOs Max field.
  const [countText, setCountText] = useState('');
  const [everyText, setEveryText] = useState('');

  useEffect(() => {
    (async () => {
      try {
        const [c, k, st] = await Promise.all([GetWebPublishConfig(), WebPublishColumns(), GetWebPublishStatus()]);
        setCfg(c as any);
        setCols((k ?? []) as Col[]);
        setCountText(String((c as any).count ?? 100));
        setEveryText(String((c as any).interval_min ?? 0));
        const s: any = st;
        if (s?.last_err) setErr(s.last_err);
        else if (s?.last_run) setMsg(t('wpub.lastRun') + ' ' + s.last_run);
      } catch (e: any) { setErr(String(e?.message ?? e)); }
    })();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  if (!cfg) return <p className="text-xs text-muted-foreground">…</p>;
  const set = (p: Partial<Cfg>) => setCfg((c) => (c ? { ...c, ...p } : c));

  // Every control saves immediately: this panel has no Save button of its own,
  // matching the other "saved instantly" panels.
  const save = async (next: Cfg) => {
    setCfg(next);
    try { await SaveWebPublishConfig(next as any); setErr(''); }
    catch (e: any) { setErr(String(e?.message ?? e)); }
  };
  const patch = (p: Partial<Cfg>) => save({ ...cfg, ...p });

  const toggleCol = (key: string) => {
    const has = cfg.columns?.includes(key);
    patch({ columns: has ? cfg.columns.filter((c) => c !== key) : [...(cfg.columns ?? []), key] });
  };

  const run = async (what: 'test' | 'publish') => {
    setBusy(what); setMsg(''); setErr('');
    try {
      const r = what === 'test' ? await TestWebPublishFTP(cfg as any) : await PublishLogNow();
      setMsg(String(r));
    } catch (e: any) { setErr(String(e?.message ?? e)); }
    finally { setBusy(''); }
  };

  return (
    <div className="space-y-4 max-w-3xl">
      <p className="text-xs text-muted-foreground leading-relaxed">{t('wpub.hint')}</p>

      <label className="flex items-center gap-2 text-sm cursor-pointer">
        <Checkbox checked={cfg.enabled} onCheckedChange={(c) => patch({ enabled: !!c })} />
        {t('wpub.enable')}
      </label>

      {cfg.enabled && (<>
        {/* ── The file ── */}
        <div className="space-y-2 border-t border-border/60 pt-3">
          <Label className="text-xs font-semibold">{t('wpub.fileSection')}</Label>
          <div className="grid grid-cols-[130px_1fr] gap-2 items-center">
            <Label className="text-sm">{t('wpub.format')}</Label>
            <Select value={cfg.format} onValueChange={(v) => patch({ format: v })}>
              <SelectTrigger className="h-8 w-56"><SelectValue /></SelectTrigger>
              <SelectContent>
                <SelectItem value="html">{t('wpub.formatHtml')}</SelectItem>
                <SelectItem value="csv">{t('wpub.formatCsv')}</SelectItem>
              </SelectContent>
            </Select>

            <Label className="text-sm">{t('wpub.folder')}</Label>
            <div className="flex gap-2">
              <Input className="h-8 font-mono text-xs flex-1" value={cfg.folder}
                onChange={(e) => set({ folder: e.target.value })} onBlur={() => patch({ folder: cfg.folder })} />
              <Button variant="outline" size="sm" className="h-8" onClick={async () => {
                try { const p = await PickBackupFolder(); if (p) patch({ folder: p }); } catch { /* cancelled */ }
              }}><FolderOpen className="size-3.5" /> {t('wpub.browse')}</Button>
            </div>

            <Label className="text-sm">{t('wpub.fileName')}</Label>
            <Input className="h-8 w-56 font-mono text-xs" value={cfg.file_name}
              onChange={(e) => set({ file_name: e.target.value })} onBlur={() => patch({ file_name: cfg.file_name })} />

            <Label className="text-sm">{t('wpub.title')}</Label>
            <Input className="h-8" placeholder={t('wpub.titlePh')} value={cfg.title}
              onChange={(e) => set({ title: e.target.value })} onBlur={() => patch({ title: cfg.title })} />

            <Label className="text-sm">{t('wpub.count')}</Label>
            <Input type="number" min={1} max={100000} className="h-8 w-28 font-mono text-xs" value={countText}
              onChange={(e) => setCountText(e.target.value)}
              onBlur={() => {
                const n = Math.floor(Number(countText));
                if (Number.isFinite(n) && n > 0) patch({ count: n }); else setCountText(String(cfg.count));
              }} />

            <Label className="text-sm">{t('wpub.every')}</Label>
            <div className="flex items-center gap-2">
              <Input type="number" min={0} max={1440} className="h-8 w-28 font-mono text-xs" value={everyText}
                onChange={(e) => setEveryText(e.target.value)}
                onBlur={() => {
                  const n = Math.floor(Number(everyText));
                  if (Number.isFinite(n) && n >= 0) patch({ interval_min: n }); else setEveryText(String(cfg.interval_min));
                }} />
              <span className="text-xs text-muted-foreground">{t('wpub.everyHint')}</span>
            </div>
          </div>
        </div>

        {/* ── Columns ── */}
        <div className="space-y-2 border-t border-border/60 pt-3">
          <div className="flex items-center justify-between">
            <Label className="text-xs font-semibold">{t('wpub.columns')}</Label>
            <span className="text-[11px] text-muted-foreground">
              {t('wpub.columnsCount', { n: cfg.columns?.length ?? 0, total: cols.length })}
            </span>
          </div>

          {/* CHOSEN, in publication order — this is the list that answers "what
              will the page look like", which a sectioned catalogue cannot. */}
          {(cfg.columns?.length ?? 0) > 0 && (
            <div className="flex flex-wrap gap-1.5">
              {cfg.columns.map((k) => {
                const c = cols.find((x) => x.key === k);
                return (
                  <button key={k} type="button" onClick={() => toggleCol(k)}
                    title={t('wpub.removeColumn')}
                    className="px-2 py-0.5 rounded-full border border-primary bg-primary text-primary-foreground text-[11px] font-medium">
                    {c?.header ?? k} ×
                  </button>
                );
              })}
            </div>
          )}

          {/* One dropdown, alphabetical, filtered as you type. The catalogue is
              123 fields: laid out on the page it buries every other setting, and
              sorting by anything but the alphabet means hunting. The menu stays
              open while ticking — picking eight columns should be one visit. */}
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button variant="outline" size="sm" className="w-full justify-between h-8 text-xs font-normal">
                {t('wpub.columnsPick')}
                <ChevronsUpDown className="size-3.5 opacity-60" />
              </Button>
            </DropdownMenuTrigger>
            {/* The search box is OUTSIDE the scrolling area, not sticky inside it.
                Sticky kept it in place but the rows scrolled over it: a menu item
                carries its own background and its own stacking, so it wins over a
                sticky sibling however high its z-index. A header that never
                scrolls has nothing to lose the fight with. */}
            <DropdownMenuContent align="start" className="w-72 p-0 flex flex-col max-h-80">
              <div className="p-1.5 border-b border-border/60 bg-popover shrink-0">
                <Input className="h-7 text-xs" placeholder={t('wpub.columnsSearch')}
                  value={colSearch}
                  onChange={(e) => setColSearch(e.target.value)}
                  onKeyDown={(e) => e.stopPropagation()} />
              </div>
              <div className="overflow-y-auto p-1">
              {[...cols]
                .sort((a, b) => a.header.localeCompare(b.header))
                .filter((c) => {
                  const q = colSearch.trim().toLowerCase();
                  return !q || c.header.toLowerCase().includes(q) || c.key.toLowerCase().includes(q);
                })
                .map((c) => (
                  <DropdownMenuCheckboxItem
                    key={c.key}
                    checked={cfg.columns?.includes(c.key) ?? false}
                    onCheckedChange={() => toggleCol(c.key)}
                    onSelect={(e) => e.preventDefault()}
                    className="text-xs"
                  >
                    {c.header}
                    <span className="ml-auto pl-2 text-[10px] text-muted-foreground font-mono">{c.group}</span>
                  </DropdownMenuCheckboxItem>
                ))}
              </div>
            </DropdownMenuContent>
          </DropdownMenu>
          <p className="text-[11px] text-muted-foreground">{t('wpub.columnsHint')}</p>
        </div>

        {/* ── Upload ── */}
        <div className="space-y-2 border-t border-border/60 pt-3">
          <label className="flex items-center gap-2 text-sm cursor-pointer">
            <Checkbox checked={cfg.ftp_enabled} onCheckedChange={(c) => patch({ ftp_enabled: !!c })} />
            {t('wpub.ftpEnable')}
          </label>
          {cfg.ftp_enabled && (
            <div className="grid grid-cols-[130px_1fr] gap-2 items-center">
              <Label className="text-sm">{t('wpub.ftpHost')}</Label>
              <div className="flex gap-2">
                <Input className="h-8 flex-1" placeholder="ftp.example.com" value={cfg.ftp_host}
                  onChange={(e) => set({ ftp_host: e.target.value })} onBlur={() => patch({ ftp_host: cfg.ftp_host })} />
                <Input type="number" className="h-8 w-24 font-mono text-xs" value={cfg.ftp_port}
                  onChange={(e) => set({ ftp_port: Number(e.target.value) || 21 })}
                  onBlur={() => patch({ ftp_port: cfg.ftp_port })} />
              </div>
              <Label className="text-sm">{t('wpub.ftpUser')}</Label>
              <Input className="h-8" value={cfg.ftp_user}
                onChange={(e) => set({ ftp_user: e.target.value })} onBlur={() => patch({ ftp_user: cfg.ftp_user })} />
              <Label className="text-sm">{t('wpub.ftpPassword')}</Label>
              <Input type="password" className="h-8" value={cfg.ftp_password}
                onChange={(e) => set({ ftp_password: e.target.value })} onBlur={() => patch({ ftp_password: cfg.ftp_password })} />
              <Label className="text-sm">{t('wpub.ftpFolder')}</Label>
              <Input className="h-8 font-mono text-xs" placeholder="/www/log" value={cfg.ftp_folder}
                onChange={(e) => set({ ftp_folder: e.target.value })} onBlur={() => patch({ ftp_folder: cfg.ftp_folder })} />
              <Label className="text-sm">{t('wpub.ftpFileName')}</Label>
              <Input className="h-8 w-56 font-mono text-xs" value={cfg.ftp_file_name}
                onChange={(e) => set({ ftp_file_name: e.target.value })} onBlur={() => patch({ ftp_file_name: cfg.ftp_file_name })} />
              <span />
              <label className="flex items-center gap-2 text-sm cursor-pointer">
                <Checkbox checked={cfg.ftp_tls} onCheckedChange={(c) => patch({ ftp_tls: !!c })} />
                {t('wpub.ftpTls')}
              </label>
            </div>
          )}
        </div>

        <div className="flex items-center gap-3 border-t border-border/60 pt-3 flex-wrap">
          <Button size="sm" onClick={() => run('publish')} disabled={busy !== ''}>
            {busy === 'publish' ? <Loader2 className="size-3.5 animate-spin" /> : <Upload className="size-3.5" />}
            {t('wpub.publishNow')}
          </Button>
          {cfg.ftp_enabled && (
            <Button variant="outline" size="sm" onClick={() => run('test')} disabled={busy !== ''}>
              {busy === 'test' ? <Loader2 className="size-3.5 animate-spin" /> : null}
              {t('wpub.testFtp')}
            </Button>
          )}
        </div>
      </>)}

      {msg && <p className="text-xs text-success break-all">{msg}</p>}
      {err && <p className="text-xs text-danger break-all">{err}</p>}
    </div>
  );
}
