import { useEffect, useMemo, useState } from 'react';
import { X, Plus, Loader2 } from 'lucide-react';
import { SearchAwardReferences, GetAwardDefs, GetAwardReferenceMeta } from '../../wailsjs/go/main/App';
import {
  Select, SelectTrigger, SelectValue, SelectContent, SelectItem,
} from '@/components/ui/select';

type AwardRef = { code: string; name: string; dxcc: number; group: string; subgrp: string };
type AwardDef = { code: string; name: string; field?: string; dxcc_filter?: number[] | null; dynamic?: boolean };
type Meta = { code: string; count: number; can_update: boolean };

// Fields auto-derived from structured QSO data — their awards (DXCC/WAZ/WAS/…)
// are computed, never manually picked, so they don't belong in this picker.
// Fields purely derived from the callsign / cty.dat — their awards are computed,
// never picked. NB: 'state' and 'cnty' are NOT here — they're operator-settable
// QSO fields driving predefined-list awards (WAS/RAC/WAJA/JCC), so they ARE
// pickable (a lookup rarely fills the JA prefecture or VE province).
const COMPUTED_FIELDS = new Set(['dxcc', 'cqz', 'ituz', 'prefix', 'callsign', 'cont', 'country', 'grid']);

// If DXCC-filtered auto-results exceed this, require the user to type instead.
const AUTO_SHOW_MAX = 100;

interface Props {
  dxcc?: number;
  // Semicolon-delimited "AWARD@REF" entries, e.g. "POTA@FR-11553;IOTA@EU-064"
  value: string;
  onChange: (v: string) => void;
}

export function AwardRefSelector({ dxcc, value, onChange }: Props) {
  const [defs, setDefs] = useState<AwardDef[]>([]);
  const [metas, setMetas] = useState<Record<string, Meta>>({});
  const [awardCode, setAwardCode] = useState('POTA');

  const [q, setQ] = useState('');
  // autoResults: loaded immediately when award/dxcc changes (empty query, DXCC-filtered).
  // Shown when q is short and count ≤ AUTO_SHOW_MAX (e.g. 5 IOTA refs for France).
  const [autoResults, setAutoResults] = useState<AwardRef[]>([]);
  // searchResults: loaded when user types 2+ chars.
  const [searchResults, setSearchResults] = useState<AwardRef[]>([]);
  const [busy, setBusy] = useState(false);
  const [selectedRef, setSelectedRef] = useState<AwardRef | null>(null);
  const [selectedEntry, setSelectedEntry] = useState<string | null>(null);

  const entries = value ? value.split(';').filter(Boolean) : [];

  useEffect(() => {
    Promise.all([GetAwardDefs(), GetAwardReferenceMeta()])
      .then(([d, m]) => {
        setDefs((d ?? []) as any);
        setMetas(Object.fromEntries(((m ?? []) as Meta[]).map((x) => [String(x.code).toUpperCase(), x])));
      })
      .catch(() => {});
  }, []);

  // An award is offered when its DXCC scope matches the contacted entity (or it
  // has no scope) AND it has references to pick from (a loaded list, an online
  // list, or dynamic references like POTA). This is why DDFM (scope 227) shows
  // for a French call but not for others.
  const awards = useMemo(() => {
    return defs.filter((d) => {
      // Computed awards (field = dxcc/state/cqz/…) are derived automatically.
      if (COMPUTED_FIELDS.has(String(d.field ?? '').toLowerCase())) return false;
      const m = metas[String(d.code).toUpperCase()];
      const hasRefs = (m?.count ?? 0) > 0 || !!m?.can_update || !!d.dynamic;
      if (!hasRefs) return false;
      const scope = d.dxcc_filter ?? [];
      if (scope.length > 0 && (!dxcc || !scope.includes(dxcc))) return false;
      return true;
    }).map((d) => ({ code: d.code, name: d.name }));
  }, [defs, metas, dxcc]);

  // Keep the selected award valid as the offered list changes with the call.
  useEffect(() => {
    if (awards.length === 0) return;
    if (!awards.find((a) => a.code === awardCode)) setAwardCode(awards[0].code);
  }, [awards, awardCode]);

  // Is the selected award a giant dynamic list (POTA/SOTA/IOTA)? Those carry a
  // per-reference DXCC so we filter by entity; predefined lists (WAS/RAC/WAJA)
  // are small and their refs may lack a per-ref DXCC, so we load them whole.
  const isDynamic = useMemo(
    () => !!defs.find((d) => d.code === awardCode)?.dynamic,
    [defs, awardCode],
  );
  // For dynamic lists, restrict to the contacted entity; otherwise load all.
  const refDxcc = isDynamic ? (dxcc ?? 0) : 0;

  // Auto-load refs on award/dxcc change with empty query. Fetches AUTO_SHOW_MAX+1
  // so we can distinguish "all results shown" from "too many to list".
  useEffect(() => {
    setAutoResults([]);
    // Dynamic lists need an entity to scope to; predefined lists load regardless.
    if (isDynamic && !dxcc) return;
    SearchAwardReferences(awardCode, '', refDxcc, AUTO_SHOW_MAX + 1)
      .then((r) => setAutoResults((r ?? []) as any))
      .catch(() => {});
  }, [awardCode, dxcc, isDynamic, refDxcc]);

  // Typed search (2+ chars).
  useEffect(() => {
    if (q.length < 2) { setSearchResults([]); return; }
    const t = window.setTimeout(async () => {
      setBusy(true);
      try {
        const r = await SearchAwardReferences(awardCode, q, refDxcc, 50);
        setSearchResults((r ?? []) as any);
      } catch { setSearchResults([]); }
      finally { setBusy(false); }
    }, 200);
    return () => window.clearTimeout(t);
  }, [awardCode, q, refDxcc]);

  const tooManyAuto = autoResults.length > AUTO_SHOW_MAX;
  // When q is empty/short: show auto-results (if ≤ AUTO_SHOW_MAX); when typing: show search results.
  const results: AwardRef[] = q.length >= 2 ? searchResults : (tooManyAuto ? [] : autoResults);

  function addRef(ref: AwardRef) {
    const entry = `${awardCode}@${ref.code}`;
    if (!entries.includes(entry)) {
      onChange([...entries, entry].join(';'));
    }
  }

  function removeEntry(entry: string) {
    const next = entries.filter((e) => e !== entry).join(';');
    onChange(next);
    if (selectedEntry === entry) setSelectedEntry(null);
  }

  return (
    <div className="flex gap-2 h-[210px]">
      {/* Left panel */}
      <div className="flex flex-col gap-1.5 flex-1 min-w-0">

        <Select
          value={awardCode}
          onValueChange={(v) => { setAwardCode(v); setSelectedRef(null); setQ(''); setSearchResults([]); }}
        >
          <SelectTrigger className="h-7 text-xs">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            {awards.map((a) => (
              <SelectItem key={a.code} value={a.code}>{a.code}</SelectItem>
            ))}
          </SelectContent>
        </Select>

        {/* Group / Sub from selected ref */}
        <div className="grid grid-cols-[38px_1fr] items-center gap-x-1.5 gap-y-0.5 text-xs">
          <span className="text-muted-foreground text-[11px]">Group</span>
          <span className="font-mono truncate text-[11px]">{selectedRef?.group || '—'}</span>
          <span className="text-muted-foreground text-[11px]">Sub</span>
          <span className="font-mono truncate text-[11px]">{selectedRef?.subgrp || '—'}</span>
        </div>

        {/* Selected ref chip */}
        {selectedRef ? (
          <div className="flex items-center gap-1.5 h-6 px-2 rounded border border-emerald-300 bg-emerald-50 text-emerald-800 text-xs min-w-0">
            <span className="font-mono font-semibold shrink-0">{selectedRef.code}</span>
            <span className="truncate text-[10px] text-emerald-700">{selectedRef.name}</span>
            <button className="ml-auto shrink-0 hover:text-emerald-950" onClick={() => setSelectedRef(null)}>
              <X className="size-3" />
            </button>
          </div>
        ) : (
          <div className="h-6 flex items-center px-2 text-[11px] text-muted-foreground italic border border-dashed border-border rounded">
            ← pick a reference
          </div>
        )}

        {/* Add — references are always scoped to the contacted DXCC */}
        <div className="flex items-center gap-2">
          <button
            disabled={!selectedRef}
            onClick={() => selectedRef && addRef(selectedRef)}
            className="flex items-center gap-1 h-6 px-2 text-xs rounded border border-border hover:bg-accent disabled:opacity-40 disabled:cursor-not-allowed"
          >
            <Plus className="size-3" />Add
          </button>
          <span className="text-[11px] text-muted-foreground">
            {dxcc ? `DXCC #${dxcc}` : 'Enter a callsign first'}
          </span>
        </div>

        <div className="h-px bg-border shrink-0" />

        {/* Added refs list */}
        <div className="flex-1 overflow-auto space-y-0.5 min-h-0">
          {entries.length === 0 ? (
            <p className="text-[11px] text-muted-foreground italic py-0.5">No references added yet</p>
          ) : (
            entries.map((entry) => (
              <div
                key={entry}
                className={`flex items-center gap-1.5 px-2 py-0.5 rounded text-xs cursor-pointer select-none ${
                  selectedEntry === entry ? 'bg-accent' : 'hover:bg-accent/50'
                }`}
                onClick={() => setSelectedEntry(selectedEntry === entry ? null : entry)}
              >
                <span className="font-mono font-semibold flex-1 truncate">{entry}</span>
                <button
                  className="shrink-0 hover:text-destructive"
                  onClick={(e) => { e.stopPropagation(); removeEntry(entry); }}
                >
                  <X className="size-3" />
                </button>
              </div>
            ))
          )}
        </div>
      </div>

      {/* Right panel: reference search */}
      <div className="w-[172px] shrink-0 flex flex-col gap-1.5 border-l pl-2 min-w-0">
        <span className="text-xs font-semibold">References</span>
        <input
          className="h-6 w-full rounded border border-input bg-background px-2 text-xs focus:outline-none focus:ring-1 focus:ring-ring"
          placeholder="Search…"
          value={q}
          onChange={(e) => setQ(e.target.value)}
        />
        <div className="flex-1 overflow-auto border rounded-md text-xs min-h-0">
          {busy && (
            <div className="flex items-center gap-1.5 px-2 py-1.5 text-muted-foreground">
              <Loader2 className="size-3 animate-spin" />Searching…
            </div>
          )}
          {/* Too many auto-results → require typed search */}
          {!busy && q.length < 2 && tooManyAuto && (
            <div className="px-2 py-1.5 text-[11px] text-muted-foreground leading-snug">
              Type 2+ chars to search
            </div>
          )}
          {/* Empty short-query state: prompt for a callsign (dynamic lists) or
              note the list is empty (predefined awards with no references). */}
          {!busy && q.length < 2 && !tooManyAuto && autoResults.length === 0 && (
            <div className="px-2 py-1.5 text-[11px] text-muted-foreground leading-snug">
              {isDynamic && !dxcc
                ? 'Enter a callsign, or type to search.'
                : 'No references for this entity.'}
            </div>
          )}
          {/* Typed search, no results */}
          {!busy && q.length >= 2 && results.length === 0 && (
            <div className="px-2 py-2 text-[11px] text-muted-foreground leading-snug">
              No results.
              <br />
              <span className="text-[10px]">Download reference lists in the Awards panel → Import data.</span>
            </div>
          )}
          {results.map((r) => (
            <div
              key={r.code}
              className={`px-2 py-1 cursor-pointer border-b border-border/30 last:border-0 ${
                selectedRef?.code === r.code ? 'bg-accent' : 'hover:bg-accent/50'
              }`}
              onClick={() => setSelectedRef(r)}
              onDoubleClick={() => { setSelectedRef(r); addRef(r); }}
            >
              <div className="font-mono font-semibold leading-tight text-[11px]">{r.code}</div>
              {r.name && (
                <div className="text-[10px] text-muted-foreground leading-tight truncate">{r.name}</div>
              )}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}
