import { useCallback, useEffect, useMemo, useState } from 'react';
import { RefreshCw, Star, ExternalLink } from 'lucide-react';
import { GetDXpeditions, GetDXWorldNews, RefreshDXpeditions, WatchlistEntries, WatchlistAdd } from '../../wailsjs/go/main/App';
import { BrowserOpenURL, EventsOn } from '../../wailsjs/runtime/runtime';
import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';
import { useI18n } from '@/lib/i18n';

// DXpeditions — the two feeds the DX world announces itself on, side by side.
//
// Left: NG3K's ADXO, the structured announcements, each judged against THIS log
// so the list reads as "what I still need" rather than "what is on". Right:
// DX-World's headlines, whose callsigns are mined out of the title so they can
// be watched with the same one click.

type DXped = {
  dxcc: string; callsign: string; calls?: string[];
  start_date: string; end_date: string;
  bands?: string[]; modes?: string[];
  qsl: string; operators: string; source: string; link: string;
  status: string;          // active | upcoming
  status_chase: string;    // new | new-band-mode | new-band | new-mode | new-slot | worked | ''
  unconfirmed?: boolean;
};

type News = {
  title: string; link: string; pub_date: string; excerpt: string;
  creator: string; image_url: string; tag: string; calls?: string[];
};

// One badge per expedition, the strongest verdict winning — the same palette
// and the same words the cluster uses, so the two views teach one vocabulary.
const CHASE_BADGE: Record<string, { label: string; colour: string }> = {
  'new':           { label: 'clg2.newDxcc',     colour: 'var(--danger)' },
  'new-band-mode': { label: 'clg2.newBandMode', colour: 'var(--danger)' },
  'new-band':      { label: 'clg2.newBand',     colour: 'var(--warning)' },
  'new-mode':      { label: 'clg2.newMode',     colour: 'var(--caution)' },
  'new-slot':      { label: 'clg2.newSlot',     colour: '#5AC8FA' },
  'worked':        { label: 'wl.worked',        colour: 'var(--info)' },
};

export function DXpeditionsPanel() {
  const { t } = useI18n();
  const [peds, setPeds] = useState<DXped[]>([]);
  const [news, setNews] = useState<News[]>([]);
  const [watched, setWatched] = useState<Set<string>>(new Set());
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState('');
  const [neededOnly, setNeededOnly] = useState(() => localStorage.getItem('opslog.dxpedNeeded') === '1');

  const loadWatchlist = useCallback(async () => {
    try {
      const e: any[] = await WatchlistEntries();
      setWatched(new Set((e ?? []).map((x) => String(x.callsign ?? '').toUpperCase())));
    } catch { /* the list simply shows every call as unwatched */ }
  }, []);

  const load = useCallback(async () => {
    setBusy(true);
    setErr('');
    const [p, n] = await Promise.allSettled([GetDXpeditions(), GetDXWorldNews()]);
    if (p.status === 'fulfilled') setPeds((p.value as any) ?? []);
    else setErr(String((p.reason as any)?.message ?? p.reason));
    if (n.status === 'fulfilled') setNews((n.value as any) ?? []);
    setBusy(false);
  }, []);

  useEffect(() => { void load(); void loadWatchlist(); }, [load, loadWatchlist]);
  useEffect(() => EventsOn('watchlist:changed', () => { void loadWatchlist(); }), [loadWatchlist]);

  const refresh = async () => { await RefreshDXpeditions(); await load(); };

  const addAll = async (calls: string[]) => {
    for (const c of calls) {
      if (!watched.has(c.toUpperCase())) {
        try { await WatchlistAdd(c, false); } catch { /* reported by the notice */ }
      }
    }
    await loadWatchlist();
  };

  const shown = useMemo(
    () => (neededOnly ? peds.filter((p) => p.status_chase && p.status_chase !== 'worked') : peds),
    [peds, neededOnly]);

  // A row's calls: the mined ones, else whatever the announcement called it.
  const callsOf = (p: DXped) => (p.calls?.length ? p.calls : p.callsign ? [p.callsign] : []);

  return (
    <div className="flex h-full min-h-0 gap-3">
      {/* ── Announcements (ADXO) ── */}
      <section className="flex flex-col min-h-0 flex-[3] rounded-lg border border-border bg-card overflow-hidden">
        <header className="flex items-center gap-2 px-3 py-2 border-b border-border shrink-0">
          <span className="text-sm font-semibold">{t('dxp.announced')}</span>
          <span className="text-[11px] text-muted-foreground">{t('dxp.source', { name: 'NG3K ADXO' })}</span>
          <label className="ml-auto flex items-center gap-1.5 text-[11px] cursor-pointer text-muted-foreground hover:text-foreground">
            <input type="checkbox" checked={neededOnly}
              onChange={(e) => { setNeededOnly(e.target.checked); localStorage.setItem('opslog.dxpedNeeded', e.target.checked ? '1' : '0'); }} />
            {t('dxp.neededOnly')}
          </label>
          <Button variant="outline" size="sm" onClick={refresh} disabled={busy}>
            <RefreshCw className={cn('size-3.5', busy && 'animate-spin')} /> {t('dxp.refresh')}
          </Button>
        </header>

        {err && <div className="px-3 py-2 text-xs text-danger shrink-0">{err}</div>}

        <div className="flex-1 min-h-0 overflow-y-auto p-2 space-y-1.5">
          {shown.length === 0 && !busy && (
            <p className="text-xs text-muted-foreground text-center py-6">{t('dxp.none')}</p>
          )}
          {shown.map((p, i) => {
            const calls = callsOf(p);
            const badge = CHASE_BADGE[p.status_chase];
            const allWatched = calls.length > 0 && calls.every((c) => watched.has(c.toUpperCase()));
            return (
              <article key={`${p.callsign}-${p.start_date}-${i}`}
                className={cn('rounded-md border p-2 text-xs',
                  p.status === 'active' ? 'border-success/40 bg-success/5' : 'border-border bg-muted/20')}>
                <div className="flex items-center gap-2 flex-wrap">
                  <span className="font-mono font-bold text-sm text-info">{p.callsign || '—'}</span>
                  <span className="font-medium">{p.dxcc}</span>
                  {p.status === 'active' && (
                    <span className="px-1 py-px rounded text-[10px] font-bold uppercase bg-success-muted text-success-muted-foreground">
                      {t('dxp.onAir')}
                    </span>
                  )}
                  {badge && (
                    <span className="px-1 py-px rounded text-[10px] font-bold uppercase tracking-wide border"
                      title={p.unconfirmed ? t('dec.unconfTip') : undefined}
                      style={p.unconfirmed
                        ? { color: badge.colour, borderColor: badge.colour, borderStyle: 'dashed', opacity: 0.6 }
                        : { color: badge.colour, borderColor: badge.colour }}>
                      {t(badge.label)}
                    </span>
                  )}
                  <span className="ml-auto text-[11px] text-muted-foreground whitespace-nowrap">
                    {p.start_date} → {p.end_date}
                  </span>
                </div>

                <div className="mt-1 flex items-center gap-2 flex-wrap text-[11px] text-muted-foreground">
                  {!!p.bands?.length && <span>{p.bands.join(' · ')}</span>}
                  {!!p.modes?.length && <span className="text-foreground/70">{p.modes.join(' ')}</span>}
                  {p.qsl && <span>QSL: {p.qsl}</span>}
                  {p.source && <span>· {p.source}</span>}
                </div>
                {p.operators && <p className="mt-0.5 text-[11px] text-muted-foreground truncate">{p.operators}</p>}

                <div className="mt-1.5 flex items-center gap-2">
                  <Button variant={allWatched ? 'ghost' : 'outline'} size="sm" className="h-6 text-[11px]"
                    disabled={calls.length === 0 || allWatched}
                    onClick={() => addAll(calls)}
                    title={t('dxp.watchTip')}>
                    <Star className={cn('size-3', allWatched && 'fill-current text-warning')} />
                    {allWatched ? t('dxp.watched') : t('dxp.watch')}
                  </Button>
                  {p.link && (
                    <button type="button" onClick={() => BrowserOpenURL(p.link)}
                      className="text-[11px] text-muted-foreground hover:text-foreground inline-flex items-center gap-1">
                      <ExternalLink className="size-3" /> {t('dxp.open')}
                    </button>
                  )}
                </div>
              </article>
            );
          })}
        </div>
      </section>

      {/* ── News (DX-World) ── */}
      <section className="flex flex-col min-h-0 flex-[2] rounded-lg border border-border bg-card overflow-hidden">
        <header className="flex items-center gap-2 px-3 py-2 border-b border-border shrink-0">
          <span className="text-sm font-semibold">{t('dxp.news')}</span>
          <span className="text-[11px] text-muted-foreground">{t('dxp.source', { name: 'DX-World' })}</span>
        </header>
        <div className="flex-1 min-h-0 overflow-y-auto p-2 space-y-1.5">
          {news.length === 0 && !busy && (
            <p className="text-xs text-muted-foreground text-center py-6">{t('dxp.noNews')}</p>
          )}
          {news.map((n, i) => {
            const newsCalls = n.calls ?? [];
            const newsAllWatched = newsCalls.length > 0 && newsCalls.every((c) => watched.has(c.toUpperCase()));
            return (
            <article key={`${n.link}-${i}`} className="rounded-md border border-border bg-muted/20 p-2">
              <div className="flex items-start gap-2">
                {n.image_url && (
                  <img src={n.image_url} alt="" className="size-12 rounded object-cover shrink-0"
                    onError={(e) => { (e.currentTarget as HTMLImageElement).style.display = 'none'; }} />
                )}
                <div className="min-w-0 flex-1">
                  <div className="flex items-center gap-1.5 flex-wrap">
                    {n.tag && (
                      <span className="px-1 py-px rounded text-[9px] font-bold uppercase bg-primary/15 text-primary">{n.tag}</span>
                    )}
                    <button type="button" onClick={() => n.link && BrowserOpenURL(n.link)}
                      className="text-xs font-medium text-left hover:underline">{n.title}</button>
                  </div>
                  <p className="mt-0.5 text-[11px] text-muted-foreground line-clamp-3">{n.excerpt}</p>
                  {/* The callsigns are shown, not clicked: watching is the same
                      one button as an announcement, so the gesture is learned
                      once for the whole tab. */}
                  <div className="mt-1 flex items-center gap-1.5 flex-wrap">
                    {n.pub_date && (
                      <span className="text-[10px] text-muted-foreground">
                        {new Date(n.pub_date).toLocaleDateString()}
                      </span>
                    )}
                    {(n.calls ?? []).map((c) => (
                      <span key={c} className={cn('font-mono text-[10px]',
                        watched.has(c.toUpperCase()) ? 'text-warning' : 'text-info')}>
                        {c}
                      </span>
                    ))}
                  </div>
                  <div className="mt-1.5 flex items-center gap-2">
                    <Button variant={newsAllWatched ? 'ghost' : 'outline'} size="sm" className="h-6 text-[11px]"
                      disabled={newsCalls.length === 0 || newsAllWatched}
                      onClick={() => addAll(newsCalls)}
                      title={t('dxp.watchTip')}>
                      <Star className={cn('size-3', newsAllWatched && 'fill-current text-warning')} />
                      {newsAllWatched ? t('dxp.watched') : t('dxp.watch')}
                    </Button>
                    {n.link && (
                      <button type="button" onClick={() => BrowserOpenURL(n.link)}
                        className="text-[11px] text-muted-foreground hover:text-foreground inline-flex items-center gap-1">
                        <ExternalLink className="size-3" /> {t('dxp.open')}
                      </button>
                    )}
                  </div>
                </div>
              </div>
            </article>
            );
          })}
        </div>
      </section>
    </div>
  );
}
