import { useCallback, useEffect, useMemo, useState } from 'react';
import { UploadCloud, DownloadCloud, Search, Loader2, ScrollText, ListChecks, Trees, ExternalLink } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import {
  Select, SelectTrigger, SelectValue, SelectContent, SelectItem,
} from '@/components/ui/select';
import { cn } from '@/lib/utils';
import { FindQSOsForUpload, UploadQSOsManual, DownloadConfirmations, SyncPOTAHunterLog, ListQSO, BulkUpdateQSL, UploadCallsign } from '../../wailsjs/go/main/App';
import { Input } from '@/components/ui/input';
import { EventsOn } from '../../wailsjs/runtime/runtime';

type UploadRow = {
  id: number; qso_date: string; callsign: string;
  band: string; mode: string; country: string; status: string;
};

type Confirmation = {
  callsign: string; qso_date: string; band: string; mode: string; country: string;
  new_dxcc: boolean; new_band: boolean; new_slot: boolean;
};

const SERVICES = [
  { v: 'qrz',     label: 'QRZ.com' },
  { v: 'clublog', label: 'Club Log' },
  { v: 'hrdlog',  label: 'HRDLog.net' },
  { v: 'eqsl',    label: 'eQSL.cc' },
  { v: 'lotw',    label: 'LoTW' },
  { v: 'pota',    label: 'POTA hunter log' },
  { v: 'paper',   label: 'Paper QSL' },
];

const QSL_STATUSES = [
  { v: '_', label: '— leave —' },
  { v: 'Y', label: 'Yes' },
  { v: 'N', label: 'No' },
  { v: 'R', label: 'Requested' },
  { v: 'I', label: 'Ignore' },
];

type LogQSO = {
  id: number; qso_date: string; callsign: string; band: string; mode: string; country?: string;
  qsl_sent?: string; qsl_rcvd?: string; qsl_via?: string; qsl_sent_date?: string; qsl_rcvd_date?: string;
};

type POTAUnmatched = { activator: string; date: string; band: string; reference: string; reason: string; qso_id: number };
type POTASync = { fetched: number; updated: number; already_tagged: number; added: number; unmatched: number; unmatched_list: POTAUnmatched[]; skipped_other_call: number; my_call: string };

const SENT_STATUSES = [
  { v: 'R', label: 'Requested' },
  { v: 'N', label: 'No' },
  { v: 'Q', label: 'Queued' },
  { v: 'Y', label: 'Yes (already sent)' },
  { v: 'I', label: 'Invalid' },
  { v: '_', label: '— blank —' },
];

function fmtDate(iso: string): string {
  if (!iso) return '';
  const d = new Date(iso);
  if (isNaN(d.getTime())) return iso;
  const p = (n: number) => String(n).padStart(2, '0');
  return `${d.getUTCFullYear()}-${p(d.getUTCMonth() + 1)}-${p(d.getUTCDate())} ${p(d.getUTCHours())}:${p(d.getUTCMinutes())}`;
}

// fmtQslDate renders a QSL/LoTW/eQSL/ClubLog date (ADIF YYYYMMDD, or an ISO
// datetime) as YYYY-MM-DD — same shape as the QSO date, without the time.
export function fmtQslDate(s?: string): string {
  if (!s) return '';
  const t = s.trim();
  const m = t.match(/^(\d{4})(\d{2})(\d{2})/);
  if (m) return `${m[1]}-${m[2]}-${m[3]}`;
  const d = new Date(t);
  if (!isNaN(d.getTime())) return d.toISOString().slice(0, 10);
  return t;
}

// QSL Manager as an in-app tab panel: upload logged QSOs to online logbooks
// and download confirmations, while the rest of the app stays usable.
export function QSLManagerPanel({ onEditQSO }: { onEditQSO?: (id: number) => void } = {}) {
  const [service, setService] = useState('lotw');
  // The callsign this profile signs/uploads/downloads as for the selected
  // service (Force station callsign, else the profile call). Shown so the user
  // knows WHICH of their calls a download/upload targets in a mixed-call log.
  const [uploadCall, setUploadCall] = useState('');
  useEffect(() => {
    if (service === 'pota' || service === 'paper') { setUploadCall(''); return; }
    UploadCallsign(service).then((c) => setUploadCall(c || '')).catch(() => setUploadCall(''));
  }, [service]);
  const [potaSyncing, setPotaSyncing] = useState(false);
  const [potaRes, setPotaRes] = useState<POTASync | null>(null);
  const [potaErr, setPotaErr] = useState('');
  const [potaAddMissing, setPotaAddMissing] = useState(false);
  // Only sync hunts made under the active profile's callsign (skip XV9Q/NQ2H…).
  const [potaOnlyMyCall, setPotaOnlyMyCall] = useState(true);

  async function syncPota() {
    setPotaSyncing(true); setPotaErr(''); setPotaRes(null);
    try { setPotaRes((await SyncPOTAHunterLog(potaAddMissing, potaOnlyMyCall)) as any as POTASync); }
    catch (e: any) { setPotaErr(String(e?.message ?? e)); }
    finally { setPotaSyncing(false); }
  }

  // ── Paper QSL: search a callsign, bulk-set sent/received + via + date ──
  const [paperCall, setPaperCall] = useState('');
  const [paperRows, setPaperRows] = useState<LogQSO[]>([]);
  const [paperSel, setPaperSel] = useState<Set<number>>(new Set());
  const [paperBusy, setPaperBusy] = useState(false);
  const [paperMsg, setPaperMsg] = useState('');
  const [qslRcvd, setQslRcvd] = useState('Y');
  const [qslSent, setQslSent] = useState('_');
  const [qslRcvdDate, setQslRcvdDate] = useState('');
  const [qslSentDate, setQslSentDate] = useState('');
  const [qslVia, setQslVia] = useState('');

  const searchPaper = useCallback(async () => {
    const c = paperCall.trim().toUpperCase();
    if (!c) return;
    setPaperBusy(true); setPaperMsg('');
    try {
      const r: any = await ListQSO({ callsign: c, limit: 1000 } as any);
      const list = (r ?? []) as LogQSO[];
      setPaperRows(list);
      setPaperSel(new Set(list.map((x) => x.id)));
    } catch (e: any) { setPaperMsg(String(e?.message ?? e)); setPaperRows([]); }
    finally { setPaperBusy(false); }
  }, [paperCall]);

  function togglePaper(id: number) {
    setPaperSel((s) => { const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n; });
  }
  const paperAllSel = paperRows.length > 0 && paperSel.size === paperRows.length;

  async function applyPaper() {
    const ids = paperRows.filter((r) => paperSel.has(r.id)).map((r) => r.id);
    if (ids.length === 0) return;
    setPaperBusy(true); setPaperMsg('');
    const ymd = (d: string) => d.replaceAll('-', '');
    try {
      const n = await BulkUpdateQSL(ids as any, {
        sent_status: qslSent === '_' ? '' : qslSent,
        rcvd_status: qslRcvd === '_' ? '' : qslRcvd,
        sent_date: ymd(qslSentDate),
        rcvd_date: ymd(qslRcvdDate),
        via: qslVia,
      } as any);
      setPaperMsg(`${n} QSO updated.`);
      await searchPaper();
    } catch (e: any) { setPaperMsg(String(e?.message ?? e)); }
    finally { setPaperBusy(false); }
  }
  const [sent, setSent] = useState('R');
  const [rows, setRows] = useState<UploadRow[]>([]);
  const [selected, setSelected] = useState<Set<number>>(new Set());
  const [searching, setSearching] = useState(false);
  const [error, setError] = useState('');
  const [addNotFound, setAddNotFound] = useState(false);
  // Download date window: 'last' = incremental since last pull, 'date' = from a
  // chosen date, 'all' = everything.
  const [sinceMode, setSinceMode] = useState<'last' | 'date' | 'all'>('last');
  const [sinceDate, setSinceDate] = useState('');

  const [viewMode, setViewMode] = useState<'upload' | 'confirmations'>('upload');
  const [confirmations, setConfirmations] = useState<Confirmation[]>([]);
  const [confFilter, setConfFilter] = useState('all'); // all | new | dxcc | band | slot

  const [showLog, setShowLog] = useState(false);
  const [logLines, setLogLines] = useState<string[]>([]);
  const [busy, setBusy] = useState(false);
  const [logAction, setLogAction] = useState<'upload' | 'download'>('upload');

  useEffect(() => {
    const offLog = EventsOn('qslmgr:log', (line: string) => setLogLines((p) => [...p, line]));
    const offDone = EventsOn('qslmgr:done', (d: any) => {
      setLogLines((p) => [...p, `— Done: ${d?.uploaded ?? 0}/${d?.total ?? 0} —`]);
      setBusy(false);
    });
    const offConf = EventsOn('qslmgr:confirmations', (list: any) => {
      setConfirmations((list ?? []) as Confirmation[]);
      setViewMode('confirmations');
    });
    return () => { offLog(); offDone(); offConf(); };
  }, []);

  const selectedCount = selected.size;
  const allSelected = rows.length > 0 && selected.size === rows.length;
  const serviceLabel = useMemo(() => SERVICES.find((s) => s.v === service)?.label ?? service, [service]);

  const shownConfs = useMemo(() => confirmations.filter((c) => {
    switch (confFilter) {
      case 'new':  return c.new_dxcc || c.new_band || c.new_slot;
      case 'dxcc': return c.new_dxcc;
      case 'band': return c.new_band;
      case 'slot': return c.new_slot;
      default:     return true;
    }
  }), [confirmations, confFilter]);

  const selectRequired = useCallback(async () => {
    setSearching(true);
    setError('');
    try {
      const r: any = await FindQSOsForUpload(service, sent === '_' ? '' : sent);
      const list = (r ?? []) as UploadRow[];
      setRows(list);
      setSelected(new Set(list.map((x) => x.id)));
      setViewMode('upload');
      setShowLog(false);
    } catch (e: any) {
      setError(String(e?.message ?? e));
      setRows([]);
      setSelected(new Set());
    } finally {
      setSearching(false);
    }
  }, [service, sent]);

  function toggle(id: number) {
    setSelected((s) => {
      const n = new Set(s);
      if (n.has(id)) n.delete(id); else n.add(id);
      return n;
    });
  }
  function toggleAll() {
    setSelected(allSelected ? new Set() : new Set(rows.map((r) => r.id)));
  }

  async function upload() {
    const ids = rows.filter((r) => selected.has(r.id)).map((r) => r.id);
    if (ids.length === 0) return;
    setLogLines([]); setBusy(true); setLogAction('upload'); setShowLog(true);
    try { await UploadQSOsManual(service, ids); }
    catch (e: any) { setLogLines((p) => [...p, 'Error: ' + String(e?.message ?? e)]); setBusy(false); }
  }

  async function download() {
    // Resolve the date window into the backend's `since` argument:
    //   'all'  → ""           (everything)
    //   'last' → "last"       (incremental since last successful pull)
    //   'date' → "YYYY-MM-DD" (the chosen date; falls back to all if empty)
    const since = sinceMode === 'last' ? 'last' : sinceMode === 'date' ? sinceDate.trim() : '';
    setLogLines([]); setBusy(true); setLogAction('download'); setShowLog(true);
    try { await DownloadConfirmations(service, addNotFound, since); }
    catch (e: any) { setLogLines((p) => [...p, 'Error: ' + String(e?.message ?? e)]); setBusy(false); }
  }

  function viewResults() {
    setShowLog(false);
    if (logAction === 'upload') selectRequired();
  }

  return (
    <div className="flex flex-col min-h-0 flex-1">
      {/* Search toolbar */}
      <div className="flex items-end gap-3 px-3 py-2 border-b border-border bg-muted/20 shrink-0">
        <div className="flex flex-col gap-1">
          <label className="text-[10px] uppercase tracking-wider text-muted-foreground">Service</label>
          <Select value={service} onValueChange={setService}>
            <SelectTrigger className="h-8 w-36"><SelectValue /></SelectTrigger>
            <SelectContent>{SERVICES.map((s) => <SelectItem key={s.v} value={s.v}>{s.label}</SelectItem>)}</SelectContent>
          </Select>
        </div>
        {uploadCall && (
          <div className="flex flex-col gap-1">
            <label className="text-[10px] uppercase tracking-wider text-muted-foreground">Callsign</label>
            <span
              className="h-8 inline-flex items-center rounded border border-border bg-muted/40 px-2 font-mono text-sm font-semibold"
              title="Upload/download is scoped to this callsign (Force station callsign, else the active profile's call)"
            >
              {uploadCall}
            </span>
          </div>
        )}
        {service === 'pota' ? (
          <>
            <Button size="sm" className="h-8" onClick={syncPota} disabled={potaSyncing}>
              {potaSyncing ? <Loader2 className="size-3.5 animate-spin" /> : <Trees className="size-3.5" />}
              Sync hunter log
            </Button>
            <label className="flex items-center gap-1.5 text-[11px] text-muted-foreground cursor-pointer self-center" title="Only sync hunts made under your active profile's callsign — skip QSOs you made under another call (e.g. XV9Q, NQ2H) that aren't in this logbook">
              <Checkbox checked={potaOnlyMyCall} onCheckedChange={(c) => setPotaOnlyMyCall(!!c)} />
              Only my profile callsign
            </label>
            <label className="flex items-center gap-1.5 text-[11px] text-muted-foreground cursor-pointer self-center" title="Insert hunter-log contacts whose callsign isn't in your log yet (callsign/date/band/mode/park)">
              <Checkbox checked={potaAddMissing} onCheckedChange={(c) => setPotaAddMissing(!!c)} />
              Add not-found QSOs to my log
            </label>
            <span className="text-[11px] text-muted-foreground self-center">Token in Settings → External services → POTA.</span>
          </>
        ) : service === 'paper' ? (
          <>
            <div className="flex flex-col gap-1">
              <label className="text-[10px] uppercase tracking-wider text-muted-foreground">Callsign</label>
              <Input className="h-8 w-40 font-mono uppercase" value={paperCall}
                onChange={(e) => setPaperCall(e.target.value)}
                onKeyDown={(e) => { if (e.key === 'Enter') searchPaper(); }}
                placeholder="e.g. DL1ABC" />
            </div>
            <Button size="sm" className="h-8" onClick={searchPaper} disabled={paperBusy || !paperCall.trim()}>
              {paperBusy ? <Loader2 className="size-3.5 animate-spin" /> : <Search className="size-3.5" />}
              Search
            </Button>
            <span className="text-[11px] text-muted-foreground self-center">Find a callsign, then set QSL sent/received + via + date on the selection.</span>
          </>
        ) : (
          <>
            <div className="flex flex-col gap-1">
              <label className="text-[10px] uppercase tracking-wider text-muted-foreground">Sent status</label>
              <Select value={sent} onValueChange={setSent}>
                <SelectTrigger className="h-8 w-44"><SelectValue /></SelectTrigger>
                <SelectContent>{SENT_STATUSES.map((s) => <SelectItem key={s.v} value={s.v}>{s.label}</SelectItem>)}</SelectContent>
              </Select>
            </div>
            <Button size="sm" className="h-8" onClick={selectRequired} disabled={searching || busy}>
              {searching ? <Loader2 className="size-3.5 animate-spin" /> : <Search className="size-3.5" />}
              Select required
            </Button>
          </>
        )}
        <div className="flex-1" />
        {service === 'pota' && potaRes && (
          <span className="text-xs text-muted-foreground">
            {potaRes.updated} updated · {potaRes.added} added · {potaRes.already_tagged} already · {potaRes.unmatched} unmatched{potaRes.skipped_other_call > 0 ? ` · ${potaRes.skipped_other_call} other call` : ''} / {potaRes.fetched}
          </span>
        )}
        {service === 'paper' && paperRows.length > 0 && (
          <span className="text-xs text-muted-foreground">{paperRows.length} QSO · {paperSel.size} selected</span>
        )}
        {!showLog && viewMode === 'confirmations' && (
          <div className="flex flex-col gap-1">
            <label className="text-[10px] uppercase tracking-wider text-muted-foreground">Filter</label>
            <Select value={confFilter} onValueChange={setConfFilter}>
              <SelectTrigger className="h-8 w-36"><SelectValue /></SelectTrigger>
              <SelectContent>
                <SelectItem value="all">All</SelectItem>
                <SelectItem value="new">New (any)</SelectItem>
                <SelectItem value="dxcc">New DXCC</SelectItem>
                <SelectItem value="band">New band</SelectItem>
                <SelectItem value="slot">New slot</SelectItem>
              </SelectContent>
            </Select>
          </div>
        )}
        {logLines.length > 0 && (
          <Button variant="ghost" size="sm" className="h-8" onClick={() => (showLog ? viewResults() : setShowLog(true))}>
            {showLog ? <><ListChecks className="size-3.5" /> Results</> : <><ScrollText className="size-3.5" /> Log</>}
          </Button>
        )}
        <span className="text-xs text-muted-foreground">
          {viewMode === 'confirmations'
            ? `${shownConfs.length} / ${confirmations.length} confirmation(s)`
            : `${rows.length} found · ${selectedCount} selected`}
        </span>
      </div>

      {/* Content: log OR results grid */}
      <div className="flex-1 overflow-auto px-3 py-2 min-h-0">
        {error && <div className="text-xs text-rose-700 mb-2">{error}</div>}

        {service === 'paper' ? (
          paperRows.length === 0 ? (
            <div className="text-sm text-muted-foreground py-10 text-center">Search a callsign to list its QSOs, then set QSL status below.</div>
          ) : (
            <table className="w-full text-xs border-collapse">
              <thead className="sticky top-0 bg-card">
                <tr className="text-left text-muted-foreground border-b border-border">
                  <th className="py-1.5 px-2 w-8"><Checkbox checked={paperAllSel} onCheckedChange={() => setPaperSel(paperAllSel ? new Set() : new Set(paperRows.map((r) => r.id)))} /></th>
                  <th className="py-1.5 px-2">Date UTC</th><th className="py-1.5 px-2">Callsign</th>
                  <th className="py-1.5 px-2">Band</th><th className="py-1.5 px-2">Mode</th>
                  <th className="py-1.5 px-2">QSL Sent</th><th className="py-1.5 px-2">QSL Rcvd</th><th className="py-1.5 px-2">Via</th>
                </tr>
              </thead>
              <tbody>
                {paperRows.map((r) => (
                  <tr key={r.id}
                    className={cn('border-b border-border/40 cursor-pointer hover:bg-accent/30', paperSel.has(r.id) && 'bg-primary/5')}
                    onClick={() => togglePaper(r.id)}>
                    <td className="py-1 px-2" onClick={(e) => e.stopPropagation()}><Checkbox checked={paperSel.has(r.id)} onCheckedChange={() => togglePaper(r.id)} /></td>
                    <td className="py-1 px-2 font-mono">{fmtDate(r.qso_date)}</td>
                    <td className="py-1 px-2 font-mono font-bold">{r.callsign}</td>
                    <td className="py-1 px-2">{r.band}</td>
                    <td className="py-1 px-2">{r.mode}</td>
                    <td className="py-1 px-2 font-mono">{r.qsl_sent || '—'}{r.qsl_sent_date ? ` ${fmtQslDate(r.qsl_sent_date)}` : ''}</td>
                    <td className="py-1 px-2 font-mono">{r.qsl_rcvd || '—'}{r.qsl_rcvd_date ? ` ${fmtQslDate(r.qsl_rcvd_date)}` : ''}</td>
                    <td className="py-1 px-2 text-muted-foreground truncate max-w-[160px]">{r.qsl_via}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          )
        ) : service === 'pota' ? (
          <div className="space-y-3">
            {potaErr && <div className="text-xs rounded-md px-3 py-2 border border-destructive/30 bg-destructive/10 text-destructive">{potaErr}</div>}
            {!potaRes && !potaErr && !potaSyncing && (
              <div className="text-sm text-muted-foreground py-10 text-center">Click “Sync hunter log” to fetch your pota.app log and stamp park references.</div>
            )}
            {potaSyncing && <div className="text-sm text-muted-foreground py-10 text-center flex items-center justify-center gap-2"><Loader2 className="size-4 animate-spin" /> Syncing with pota.app…</div>}
            {potaRes && (
              <>
                <div className="text-xs rounded-md px-3 py-2 border border-emerald-300 bg-emerald-50 text-emerald-800">
                  {potaRes.updated} QSO updated · {potaRes.added} added to log · {potaRes.already_tagged} already tagged · {potaRes.unmatched} unmatched (of {potaRes.fetched} hunter-log entries).
                  {potaRes.skipped_other_call > 0 && (
                    <> {potaRes.skipped_other_call} hunt(s) made under another callsign were skipped{potaRes.my_call ? ` (kept only ${potaRes.my_call})` : ''}.</>
                  )}
                  {' '}Rescan the POTA award to count the new references.
                </div>
                {potaRes.unmatched_list?.length > 0 && (
                  <table className="w-full text-xs border-collapse">
                    <thead className="sticky top-0 bg-card">
                      <tr className="text-left text-muted-foreground border-b border-border">
                        <th className="py-1.5 px-2">Activator</th><th className="py-1.5 px-2">Date UTC</th>
                        <th className="py-1.5 px-2">Band</th><th className="py-1.5 px-2">Park</th>
                        <th className="py-1.5 px-2">Why unmatched</th>
                      </tr>
                    </thead>
                    <tbody>
                      {potaRes.unmatched_list.map((u, i) => (
                        <tr key={i}
                          className={cn('border-b border-border/40', u.qso_id > 0 && 'cursor-pointer hover:bg-accent/30')}
                          onClick={() => u.qso_id > 0 && onEditQSO?.(u.qso_id)}
                          title={u.qso_id > 0 ? 'Open this QSO to fix it' : ''}>
                          <td className="py-1 px-2 font-mono font-bold">{u.activator}</td>
                          <td className="py-1 px-2 font-mono">{u.date}</td>
                          <td className="py-1 px-2">{u.band}</td>
                          <td className="py-1 px-2 font-mono">{u.reference}</td>
                          <td className="py-1 px-2 text-muted-foreground">
                            {u.reason}
                            {u.qso_id > 0 && <ExternalLink className="inline size-3 ml-1 opacity-60" />}
                          </td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                )}
              </>
            )}
          </div>
        ) : showLog ? (
          <div className="font-mono text-[11px] space-y-0.5 py-1">
            {logLines.length === 0 ? (
              <div className="text-muted-foreground flex items-center gap-2"><Loader2 className="size-3 animate-spin" /> starting…</div>
            ) : logLines.map((l, i) => (
              <div key={i} className={cn(
                /FAIL|failed|error/i.test(l) ? 'text-rose-700'
                  : /\bOK\b|UPDATED|ADDED|uploaded/i.test(l) ? 'text-emerald-700'
                  : 'text-foreground/90')}>{l}</div>
            ))}
            {busy && <div className="text-muted-foreground flex items-center gap-2 pt-1"><Loader2 className="size-3 animate-spin" /> working…</div>}
          </div>
        ) : viewMode === 'confirmations' ? (
          shownConfs.length === 0 ? (
            <div className="text-sm text-muted-foreground py-10 text-center">
              {confirmations.length === 0 ? 'No new confirmations.' : 'No confirmations match this filter.'}
            </div>
          ) : (
            <table className="w-full text-xs border-collapse">
              <thead className="sticky top-0 bg-card">
                <tr className="text-left text-muted-foreground border-b border-border">
                  <th className="py-1.5 px-2">Date UTC</th><th className="py-1.5 px-2">Callsign</th>
                  <th className="py-1.5 px-2">Band</th><th className="py-1.5 px-2">Mode</th>
                  <th className="py-1.5 px-2">Country</th><th className="py-1.5 px-2">New?</th>
                </tr>
              </thead>
              <tbody>
                {shownConfs.map((c, i) => (
                  <tr key={i} className="border-b border-border/40">
                    <td className="py-1 px-2 font-mono">{fmtDate(c.qso_date)}</td>
                    <td className="py-1 px-2 font-mono font-bold">{c.callsign}</td>
                    <td className="py-1 px-2">{c.band}</td>
                    <td className="py-1 px-2">{c.mode}</td>
                    <td className="py-1 px-2 text-muted-foreground">{c.country}</td>
                    <td className="py-1 px-2">
                      {c.new_dxcc ? <span className="inline-block px-1.5 py-px rounded text-[9px] font-bold bg-rose-100 text-rose-800 border border-rose-300">NEW DXCC</span>
                        : c.new_band ? <span className="inline-block px-1.5 py-px rounded text-[9px] font-bold bg-amber-100 text-amber-800 border border-amber-300">NEW BAND</span>
                        : c.new_slot ? <span className="inline-block px-1.5 py-px rounded text-[9px] font-bold bg-yellow-100 text-yellow-800 border border-yellow-300">NEW SLOT</span>
                        : <span className="text-muted-foreground/50">—</span>}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          )
        ) : rows.length === 0 ? (
          <div className="text-sm text-muted-foreground py-10 text-center">Pick a service + sent status, then “Select required”.</div>
        ) : (
          <table className="w-full text-xs border-collapse">
            <thead className="sticky top-0 bg-card">
              <tr className="text-left text-muted-foreground border-b border-border">
                <th className="py-1.5 px-2 w-8"><Checkbox checked={allSelected} onCheckedChange={toggleAll} /></th>
                <th className="py-1.5 px-2">Date UTC</th><th className="py-1.5 px-2">Callsign</th>
                <th className="py-1.5 px-2">Band</th><th className="py-1.5 px-2">Mode</th>
                <th className="py-1.5 px-2">Country</th><th className="py-1.5 px-2">Sent</th>
              </tr>
            </thead>
            <tbody>
              {rows.map((r) => (
                <tr key={r.id}
                  className={cn('border-b border-border/40 cursor-pointer hover:bg-accent/30', selected.has(r.id) && 'bg-primary/5')}
                  onClick={() => toggle(r.id)}>
                  <td className="py-1 px-2" onClick={(e) => e.stopPropagation()}>
                    <Checkbox checked={selected.has(r.id)} onCheckedChange={() => toggle(r.id)} />
                  </td>
                  <td className="py-1 px-2 font-mono">{fmtDate(r.qso_date)}</td>
                  <td className="py-1 px-2 font-mono font-bold">{r.callsign}</td>
                  <td className="py-1 px-2">{r.band}</td>
                  <td className="py-1 px-2">{r.mode}</td>
                  <td className="py-1 px-2 text-muted-foreground">{r.country}</td>
                  <td className="py-1 px-2 font-mono">{r.status || '—'}</td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>

      {/* Paper-QSL apply form */}
      {service === 'paper' && (
        <div className="flex items-end flex-wrap gap-3 px-3 py-2 border-t border-border bg-muted/20 shrink-0">
          <div className="flex flex-col gap-1">
            <label className="text-[10px] uppercase tracking-wider text-muted-foreground">QSL received</label>
            <div className="flex gap-1.5">
              <Select value={qslRcvd} onValueChange={setQslRcvd}>
                <SelectTrigger className="h-8 w-28"><SelectValue /></SelectTrigger>
                <SelectContent>{QSL_STATUSES.map((s) => <SelectItem key={s.v} value={s.v}>{s.label}</SelectItem>)}</SelectContent>
              </Select>
              <Input type="date" className="h-8 w-36" value={qslRcvdDate} onChange={(e) => setQslRcvdDate(e.target.value)} title="QSL received date" />
            </div>
          </div>
          <div className="flex flex-col gap-1">
            <label className="text-[10px] uppercase tracking-wider text-muted-foreground">QSL sent</label>
            <div className="flex gap-1.5">
              <Select value={qslSent} onValueChange={setQslSent}>
                <SelectTrigger className="h-8 w-28"><SelectValue /></SelectTrigger>
                <SelectContent>{QSL_STATUSES.map((s) => <SelectItem key={s.v} value={s.v}>{s.label}</SelectItem>)}</SelectContent>
              </Select>
              <Input type="date" className="h-8 w-36" value={qslSentDate} onChange={(e) => setQslSentDate(e.target.value)} title="QSL sent date" />
            </div>
          </div>
          <div className="flex flex-col gap-1">
            <label className="text-[10px] uppercase tracking-wider text-muted-foreground">Via</label>
            <Input className="h-8 w-40" value={qslVia} onChange={(e) => setQslVia(e.target.value)} placeholder="BUREAU / DIRECT / manager" />
          </div>
          <div className="flex-1" />
          {paperMsg && <span className="text-[11px] text-muted-foreground self-center">{paperMsg}</span>}
          <Button size="sm" onClick={applyPaper} disabled={paperBusy || paperSel.size === 0}>
            Apply to {paperSel.size} selected
          </Button>
        </div>
      )}

      {/* Action bar (upload/download — not for POTA / Paper QSL) */}
      {service !== 'pota' && service !== 'paper' && (
      <div className="flex items-center justify-between gap-2 px-3 py-2 border-t border-border bg-muted/20 shrink-0">
        <div className="flex items-center gap-2 flex-wrap">
          <Button variant="outline" size="sm" onClick={download} disabled={busy}
            title="Fetch confirmations from the service and update received status">
            <DownloadCloud className="size-3.5" /> Download confirmations
          </Button>
          {/* Date window */}
          <Select value={sinceMode} onValueChange={(v) => setSinceMode(v as any)}>
            <SelectTrigger className="h-8 w-[150px] text-xs" title="How far back to download">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="last">Since last download</SelectItem>
              <SelectItem value="date">Since date…</SelectItem>
              <SelectItem value="all">All</SelectItem>
            </SelectContent>
          </Select>
          {sinceMode === 'date' && (
            <input
              type="date"
              value={sinceDate}
              onChange={(e) => setSinceDate(e.target.value)}
              className="h-8 rounded-md border border-input bg-background px-2 text-xs"
              title={service === 'qrz' ? 'QRZ: filters by QSO date (no server-side received-date filter)' : 'LoTW: confirmations received since this date'}
            />
          )}
          <label className="flex items-center gap-1.5 text-[11px] text-muted-foreground cursor-pointer" title="Insert confirmed QSOs that aren't in your log yet">
            <Checkbox checked={addNotFound} onCheckedChange={(c) => setAddNotFound(!!c)} />
            Add not-found
          </label>
        </div>
        <Button size="sm" onClick={upload} disabled={selectedCount === 0 || busy}>
          <UploadCloud className="size-3.5" /> Upload {selectedCount} to {serviceLabel}
        </Button>
      </div>
      )}
    </div>
  );
}
