import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Bell, Plus, Trash2, Volume2, Mail, Eye, X, Search } from 'lucide-react';
import {
  Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription,
} from '@/components/ui/dialog';
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 { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs';
import { cn } from '@/lib/utils';
import { useI18n } from '@/lib/i18n';
import {
  ListAlertRules, SaveAlertRule, DeleteAlertRule, GetAlertEmailTo, SetAlertEmailTo,
} from '@/../wailsjs/go/main/App';
import { alerts } from '@/../wailsjs/go/models';

type Rule = alerts.Rule;

const CONTINENTS = ['AF', 'AN', 'AS', 'EU', 'NA', 'OC', 'SA'];

function emptyRule(): Rule {
  return alerts.Rule.createFrom({
    id: '', name: 'New alert', enabled: true,
    calls: [], countries: [], continents: [], bands: [], modes: [],
    spotter_call: '', spotter_continents: [], spotter_countries: [],
    sound: true, visual: true, email: false, again_after_min: 0, skip_worked: false,
  });
}

// MultiCheck — a scrollable checkbox list for a set of options with an optional
// search box (used for the long country list). Empty selection = ALL.
function MultiCheck({ options, selected, onToggle, searchable, height = 'h-52' }: {
  options: string[]; selected: string[]; onToggle: (v: string) => void; searchable?: boolean; height?: string;
}) {
  const { t } = useI18n();
  const [q, setQ] = useState('');
  const shown = useMemo(
    () => (q ? options.filter((o) => o.toLowerCase().includes(q.toLowerCase())) : options),
    [options, q],
  );
  const sel = new Set((selected ?? []).map((s) => s.toLowerCase()));
  return (
    <div className="rounded-md border border-border">
      {searchable && (
        <div className="flex items-center gap-1.5 px-2 py-1 border-b border-border/60">
          <Search className="size-3 text-muted-foreground" />
          <input className="flex-1 bg-transparent text-xs outline-none" placeholder={t('altm.filterPh')} value={q} onChange={(e) => setQ(e.target.value)} />
        </div>
      )}
      <div className={cn('overflow-y-auto p-1', height)}>
        {shown.map((o) => (
          <label key={o} className="flex items-center gap-2 text-xs px-1.5 py-0.5 rounded hover:bg-accent/40 cursor-pointer">
            <Checkbox checked={sel.has(o.toLowerCase())} onCheckedChange={() => onToggle(o)} />
            <span className="truncate">{o}</span>
          </label>
        ))}
        {shown.length === 0 && <div className="text-[11px] text-muted-foreground px-2 py-3 text-center">{t('altm.noMatch')}</div>}
      </div>
      <div className="px-2 py-1 border-t border-border/60 text-[10px] text-muted-foreground">
        {(selected?.length ?? 0) === 0 ? t('altm.noneAll') : t('altm.nSelected', { n: selected!.length })}
      </div>
    </div>
  );
}

export function AlertsModal({ onClose, bands, modes, countries }: {
  onClose: () => void; bands: string[]; modes: string[]; countries: string[];
}) {
  const { t } = useI18n();
  const [rules, setRules] = useState<Rule[]>([]);
  const [draft, setDraft] = useState<Rule | null>(null);
  // Raw text of the callsigns box, kept separately from draft.calls. The list is
  // normalised (trim + drop empties) on the way into the rule, so binding the
  // textarea straight to calls.join('\n') round-trips every keystroke through
  // that normalisation — a trailing newline or space is stripped before React
  // re-renders, and Enter/Space appear to do nothing. Editing the raw text and
  // deriving the list from it keeps typing intact.
  const [callsText, setCallsText] = useState('');
  const [tab, setTab] = useState('def'); // active editor tab (reset to Definition on new/select)
  const [emailTo, setEmailTo] = useState('');
  const [err, setErr] = useState('');

  const refresh = useCallback(async () => {
    try { setRules(((await ListAlertRules()) ?? []) as Rule[]); }
    catch (e: any) { setErr(String(e?.message ?? e)); }
  }, []);
  useEffect(() => { refresh(); GetAlertEmailTo().then((v) => setEmailTo(v || '')).catch(() => {}); }, [refresh]);

  // loadDraft opens a rule in the editor — always through here, so the raw
  // callsigns text is re-seeded from whatever rule is now being edited.
  const loadDraft = (r: Rule | null) => {
    setDraft(r);
    setCallsText((r?.calls ?? []).join('\n'));
  };
  const patch = (p: Partial<Rule>) => setDraft((d) => (d ? alerts.Rule.createFrom({ ...d, ...p }) : d));
  const toggleIn = (key: keyof Rule, v: string) => setDraft((d) => {
    if (!d) return d;
    const cur = ((d as any)[key] as string[]) ?? [];
    const has = cur.some((x) => x.toLowerCase() === v.toLowerCase());
    const next = has ? cur.filter((x) => x.toLowerCase() !== v.toLowerCase()) : [...cur, v];
    return alerts.Rule.createFrom({ ...d, [key]: next });
  });

  // Saving used to be silent: the dialog stays open and the rule looks exactly
  // as it did a second earlier, so there was nothing to tell an operator whether
  // the click had registered. A line that says so, and clears itself.
  const [savedMsg, setSavedMsg] = useState('');
  const savedTimer = useRef(0);
  function flashSaved(text: string) {
    setSavedMsg(text);
    window.clearTimeout(savedTimer.current);
    savedTimer.current = window.setTimeout(() => setSavedMsg(''), 3000);
  }
  useEffect(() => () => window.clearTimeout(savedTimer.current), []);

  async function save() {
    if (!draft) return;
    if (!draft.name.trim()) { setErr(t('altm.giveName')); return; }
    try {
      const saved = await SaveAlertRule(draft);
      await refresh();
      loadDraft(saved as Rule);
      setErr('');
      flashSaved(t('altm.saved', { name: draft.name.trim() }));
    } catch (e: any) { setErr(String(e?.message ?? e)); }
  }
  async function del() {
    if (!draft) return;
    if (!draft.id) { loadDraft(null); return; }
    if (!window.confirm(t('altm.deleteConfirm', { name: draft.name }))) return;
    try {
      const name = draft.name;
      await DeleteAlertRule(draft.id);
      loadDraft(null);
      await refresh();
      flashSaved(t('altm.deleted', { name }));
    }
    catch (e: any) { setErr(String(e?.message ?? e)); }
  }

  return (
    <Dialog open onOpenChange={(o) => { if (!o) onClose(); }}>
      <DialogContent className="max-w-4xl">
        <DialogHeader>
          <DialogTitle className="flex items-center gap-2"><Bell className="size-4 text-primary" /> {t('altm.title')}</DialogTitle>
          <DialogDescription>{t('altm.desc')}</DialogDescription>
        </DialogHeader>

        <div className="flex gap-3 min-h-0 px-5" style={{ height: '60vh' }}>
          {/* Rule list */}
          <div className="w-56 shrink-0 flex flex-col border border-border rounded-md">
            <div className="flex items-center gap-1 px-2 py-1.5 border-b border-border/60">
              <span className="text-[11px] font-semibold uppercase tracking-wider text-muted-foreground flex-1">{t('altm.rules')}</span>
              <Button variant="ghost" size="sm" className="h-6 px-1.5" onClick={() => { loadDraft(emptyRule()); setTab('def'); }}><Plus className="size-3.5" /></Button>
            </div>
            <div className="flex-1 overflow-y-auto p-1">
              {rules.length === 0 && <div className="text-[11px] text-muted-foreground px-2 py-4 text-center">{t('altm.noRules')}</div>}
              {rules.map((r) => (
                <button key={r.id} onClick={() => { loadDraft(alerts.Rule.createFrom(r)); setTab('def'); }}
                  className={cn('w-full text-left px-2 py-1.5 rounded text-xs flex items-center gap-1.5',
                    draft?.id === r.id ? 'bg-accent text-accent-foreground font-semibold' : 'hover:bg-muted/60')}>
                  <span className={cn('size-1.5 rounded-full shrink-0', r.enabled ? 'bg-success' : 'bg-muted-foreground/40')} />
                  <span className="truncate flex-1">{r.name}</span>
                  {r.sound && <Volume2 className="size-3 text-muted-foreground shrink-0" />}
                  {r.email && <Mail className="size-3 text-muted-foreground shrink-0" />}
                </button>
              ))}
            </div>
            <div className="px-2 py-1.5 border-t border-border/60">
              <Label className="text-[10px] text-muted-foreground">{t('altm.emailTo')}</Label>
              <Input className="h-7 text-xs mt-0.5" placeholder="you@example.com" value={emailTo}
                onChange={(e) => setEmailTo(e.target.value)}
                onBlur={() => SetAlertEmailTo(emailTo).catch(() => {})} />
            </div>
          </div>

          {/* Editor */}
          <div className="flex-1 min-w-0 border border-border rounded-md flex flex-col">
            {!draft ? (
              <div className="flex-1 flex items-center justify-center text-sm text-muted-foreground">{t('altm.selectOrCreate')}</div>
            ) : (
              <Tabs value={tab} onValueChange={setTab} className="flex flex-col flex-1 min-h-0">
                <div className="flex items-center gap-2 px-2 pt-2">
                  <TabsList>
                    <TabsTrigger value="def">{t('altm.tabDef')}</TabsTrigger>
                    <TabsTrigger value="call">{t('altm.tabCall')}</TabsTrigger>
                    <TabsTrigger value="bm">{t('altm.tabBandMode')}</TabsTrigger>
                    <TabsTrigger value="orig">{t('altm.tabOrigin')}</TabsTrigger>
                  </TabsList>
                </div>

                <div className="flex-1 min-h-0 overflow-y-auto p-3">
                  <TabsContent value="def" className="mt-0 space-y-3">
                    <div>
                      <Label className="text-xs">{t('altm.ruleName')}</Label>
                      <Input value={draft.name} onChange={(e) => patch({ name: e.target.value })} />
                    </div>
                    <label className="flex items-center gap-2 text-sm cursor-pointer">
                      <Checkbox checked={draft.enabled} onCheckedChange={(c) => patch({ enabled: !!c })} /> {t('altm.alertEnabled')}
                    </label>
                    <div className="flex items-center gap-2">
                      <Label className="text-xs w-40 shrink-0">{t('altm.againAfter')}</Label>
                      <Input type="number" className="h-8 w-24" value={draft.again_after_min}
                        onChange={(e) => patch({ again_after_min: parseInt(e.target.value) || 0 })} />
                      <span className="text-[11px] text-muted-foreground">{t('altm.againHint')}</span>
                    </div>
                    <div className="border-t border-border/60 pt-3 space-y-2">
                      <Label className="text-xs font-semibold">{t('altm.actions')}</Label>
                      <div className="flex gap-4">
                        <label className="flex items-center gap-1.5 text-sm cursor-pointer"><Checkbox checked={draft.visual} onCheckedChange={(c) => patch({ visual: !!c })} /><Eye className="size-3.5" /> {t('altm.visual')}</label>
                        <label className="flex items-center gap-1.5 text-sm cursor-pointer"><Checkbox checked={draft.sound} onCheckedChange={(c) => patch({ sound: !!c })} /><Volume2 className="size-3.5" /> {t('altm.sound')}</label>
                        <label className="flex items-center gap-1.5 text-sm cursor-pointer"><Checkbox checked={draft.email} onCheckedChange={(c) => patch({ email: !!c })} /><Mail className="size-3.5" /> {t('altm.email')}</label>
                      </div>
                    </div>
                    <label className="flex items-center gap-2 text-sm cursor-pointer border-t border-border/60 pt-3">
                      <Checkbox checked={draft.skip_worked} onCheckedChange={(c) => patch({ skip_worked: !!c })} /> {t('altm.skipWorked')}
                    </label>
                  </TabsContent>

                  <TabsContent value="call" className="mt-0 grid grid-cols-2 gap-3">
                    <div className="space-y-1">
                      <Label className="text-xs">{t('altm.callsigns')}</Label>
                      <textarea className="w-full h-52 rounded-md border border-border bg-background p-2 text-xs font-mono resize-none"
                        placeholder={'DL1ABC\nIW3*\n*/P'}
                        value={callsText}
                        onChange={(e) => {
                          setCallsText(e.target.value);
                          patch({ calls: e.target.value.split('\n').map((x) => x.trim()).filter(Boolean) });
                        }} />
                    </div>
                    <div className="space-y-1">
                      <Label className="text-xs">{t('altm.countries')}</Label>
                      <MultiCheck options={countries} selected={draft.countries ?? []} onToggle={(v) => toggleIn('countries', v)} searchable />
                    </div>
                    <div className="space-y-1 col-span-2">
                      <Label className="text-xs">{t('altm.continents')}</Label>
                      <div className="flex gap-3 flex-wrap">
                        {CONTINENTS.map((c) => (
                          <label key={c} className="flex items-center gap-1.5 text-xs cursor-pointer">
                            <Checkbox checked={(draft.continents ?? []).includes(c)} onCheckedChange={() => toggleIn('continents', c)} /> {c}
                          </label>
                        ))}
                      </div>
                    </div>
                  </TabsContent>

                  <TabsContent value="bm" className="mt-0 grid grid-cols-2 gap-3">
                    <div className="space-y-1">
                      <Label className="text-xs">{t('altm.bands')}</Label>
                      <MultiCheck options={bands} selected={draft.bands ?? []} onToggle={(v) => toggleIn('bands', v)} />
                    </div>
                    <div className="space-y-1">
                      <Label className="text-xs">{t('altm.modes')}</Label>
                      <MultiCheck options={modes} selected={draft.modes ?? []} onToggle={(v) => toggleIn('modes', v)} />
                    </div>
                  </TabsContent>

                  <TabsContent value="orig" className="mt-0 grid grid-cols-2 gap-3">
                    <div className="space-y-1">
                      <Label className="text-xs">{t('altm.spotterCall')}</Label>
                      <Input className="font-mono" placeholder={t('altm.spotterCallPh')} value={draft.spotter_call ?? ''}
                        onChange={(e) => patch({ spotter_call: e.target.value })} />
                      <Label className="text-xs mt-2 block">{t('altm.spotterContinents')}</Label>
                      <div className="flex gap-3 flex-wrap">
                        {CONTINENTS.map((c) => (
                          <label key={c} className="flex items-center gap-1.5 text-xs cursor-pointer">
                            <Checkbox checked={(draft.spotter_continents ?? []).includes(c)} onCheckedChange={() => toggleIn('spotter_continents', c)} /> {c}
                          </label>
                        ))}
                      </div>
                    </div>
                    <div className="space-y-1">
                      <Label className="text-xs">{t('altm.spotterCountries')}</Label>
                      <MultiCheck options={countries} selected={draft.spotter_countries ?? []} onToggle={(v) => toggleIn('spotter_countries', v)} searchable />
                    </div>
                  </TabsContent>
                </div>

                {/* Editor actions */}
                <div className="flex items-center gap-2 px-3 py-2 border-t border-border/60">
                  {err && <span className="text-[11px] text-danger flex-1 truncate">{err}</span>}
                  {!err && savedMsg && <span className="text-[11px] text-success flex-1 truncate">{savedMsg}</span>}
                  <div className="flex-1" />
                  <Button variant="ghost" size="sm" className="text-danger" onClick={del}><Trash2 className="size-3.5" /> {t('altm.delete')}</Button>
                  <Button size="sm" onClick={save}>{t('altm.saveRule')}</Button>
                </div>
              </Tabs>
            )}
          </div>
        </div>

        <div className="flex justify-end px-5 pb-4">
          <Button variant="outline" size="sm" onClick={onClose}><X className="size-3.5" /> {t('altm.close')}</Button>
        </div>
      </DialogContent>
    </Dialog>
  );
}
