import { useCallback, useEffect, useMemo, 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 (
{searchable && (
setQ(e.target.value)} />
)}
{shown.map((o) => (
))}
{shown.length === 0 &&
{t('altm.noMatch')}
}
{(selected?.length ?? 0) === 0 ? t('altm.noneAll') : t('altm.nSelected', { n: selected!.length })}
);
}
export function AlertsModal({ onClose, bands, modes, countries }: {
onClose: () => void; bands: string[]; modes: string[]; countries: string[];
}) {
const { t } = useI18n();
const [rules, setRules] = useState([]);
const [draft, setDraft] = useState(null);
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]);
const patch = (p: Partial) => 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 });
});
async function save() {
if (!draft) return;
if (!draft.name.trim()) { setErr(t('altm.giveName')); return; }
try { const saved = await SaveAlertRule(draft); await refresh(); setDraft(saved as Rule); setErr(''); }
catch (e: any) { setErr(String(e?.message ?? e)); }
}
async function del() {
if (!draft) return;
if (!draft.id) { setDraft(null); return; }
if (!window.confirm(t('altm.deleteConfirm', { name: draft.name }))) return;
try { await DeleteAlertRule(draft.id); setDraft(null); await refresh(); }
catch (e: any) { setErr(String(e?.message ?? e)); }
}
return (
);
}