import { useEffect, useRef, useState } from 'react';
import { Satellite, Loader2 } from 'lucide-react';
import {
  Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Button } from '@/components/ui/button';
import { useI18n } from '@/lib/i18n';

export interface RecentSpotQSO {
  callsign: string;
  freqKHz: number;
  mode: string;
  band?: string;
  // Award references logged for this QSO, each one complete and ready to read
  // on a cluster line ("POTA FR-11553"). Empty for an ordinary contact.
  refs?: string[];
}

// SPOT_COMMENT_MAX is the DX cluster comment field: 30 characters, and nodes
// truncate what does not fit without saying so. Only the comment BUILT here is
// held to it — whatever the operator types is their own business.
const SPOT_COMMENT_MAX = 30;

// spotComment puts the award references after the mode, the order a cluster
// line is read in: "CW POTA FR-11553".
//
// A reference goes in whole or not at all. Truncation would leave "CW POTA" or
// half a park number on the air, which is worse than saying nothing: a spot
// nobody can act on still costs everyone who reads it.
export function spotComment(mode: string, refs?: string[]): string {
  let out = (mode || '').trim();
  for (const ref of refs ?? []) {
    const one = ref.trim();
    if (!one) continue;
    const next = out ? `${out} ${one}` : one;
    if (next.length > SPOT_COMMENT_MAX) continue; // a shorter one may still fit
    out = next;
  }
  return out;
}

interface Props {
  open: boolean;
  onClose: () => void;
  // Pre-fill values: callsign from the QSO entry (or last logged), the
  // current TX freq in kHz, and the current mode (goes into the comment).
  defaultCall: string;
  defaultFreqKHz: number;
  defaultMode: string;
  // Award references on the QSO being entered (or on the last logged one),
  // appended to the comment after the mode.
  defaultRefs?: string[];
  // Master cluster name, shown so the user knows where the spot goes.
  targetName?: string;
  recent: RecentSpotQSO[];
  onSend: (call: string, freqKHz: number, comment: string) => Promise<void>;
}

// SendSpotModal — Log4OM-style "Send Spot" window. Announces a DX spot on
// the master cluster: callsign + frequency (kHz) + a free message (defaults
// to the mode). A "Latest QSOs" list lets the operator one-click a recent
// contact into the form.
export function SendSpotModal({ open, onClose, defaultCall, defaultFreqKHz, defaultMode, defaultRefs, targetName, recent, onSend }: Props) {
  const { t } = useI18n();
  const [call, setCall] = useState('');
  const [freqKHz, setFreqKHz] = useState('');
  const [message, setMessage] = useState('');
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState('');
  const [ok, setOk] = useState(false);
  const callRef = useRef<HTMLInputElement>(null);

  // (Re)initialise the form each time the dialog opens.
  useEffect(() => {
    if (!open) return;
    setCall((defaultCall || '').toUpperCase());
    setFreqKHz(defaultFreqKHz > 0 ? trimKHz(defaultFreqKHz) : '');
    setMessage(spotComment(defaultMode, defaultRefs));
    setError('');
    setOk(false);
    // Focus the freq if the call is already known, else the call.
    setTimeout(() => callRef.current?.focus(), 50);
  }, [open, defaultCall, defaultFreqKHz, defaultMode, defaultRefs]);

  async function send() {
    const c = call.trim().toUpperCase();
    const f = parseFloat(freqKHz);
    if (!c) { setError(t('spm.callRequired')); return; }
    if (!f || f <= 0) { setError(t('spm.freqRequired')); return; }
    setBusy(true);
    setError('');
    try {
      await onSend(c, f, message.trim());
      setOk(true);
      // Brief success flash, then close.
      setTimeout(() => { setOk(false); onClose(); }, 700);
    } catch (e: any) {
      setError(String(e?.message ?? e));
    } finally {
      setBusy(false);
    }
  }

  function pick(q: RecentSpotQSO) {
    setCall(q.callsign.toUpperCase());
    if (q.freqKHz > 0) setFreqKHz(trimKHz(q.freqKHz));
    setMessage(spotComment(q.mode, q.refs));
    setError('');
  }

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

        <div className="px-5 py-3 space-y-3">
          <div className="flex gap-3">
            <div className="flex flex-col flex-1">
              <Label className="mb-1">{t('spm.callsign')}</Label>
              <Input
                ref={callRef}
                className="font-mono uppercase font-bold"
                value={call}
                onChange={(e) => setCall(e.target.value.toUpperCase())}
                onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); send(); } }}
                placeholder={t('spm.callPh')}
              />
            </div>
            <div className="flex flex-col w-32">
              <Label className="mb-1">{t('spm.frequency')}</Label>
              <Input
                className="font-mono"
                value={freqKHz}
                onChange={(e) => setFreqKHz(e.target.value)}
                onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); send(); } }}
                placeholder="14205"
              />
            </div>
          </div>
          <div className="flex flex-col">
            <Label className="mb-1">{t('spm.message')}</Label>
            <Input
              value={message}
              onChange={(e) => setMessage(e.target.value)}
              onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); send(); } }}
              placeholder={t('spm.messagePh')}
            />
          </div>

          {recent.length > 0 && (
            <div>
              <Label className="mb-1 block">{t('spm.latestQsos')}</Label>
              <div className="max-h-40 overflow-y-auto rounded-md border border-border divide-y divide-border/60">
                {recent.map((q, i) => (
                  <button
                    key={`${q.callsign}-${i}`}
                    type="button"
                    onClick={() => pick(q)}
                    className="flex w-full items-center gap-2 px-2 py-1 text-left text-xs hover:bg-accent/40"
                  >
                    <span className="font-mono font-bold w-24 truncate">{q.callsign}</span>
                    <span className="font-mono text-muted-foreground w-20 text-right">{q.freqKHz > 0 ? trimKHz(q.freqKHz) : '—'}</span>
                    <span className="text-muted-foreground">{q.mode || ''}</span>
                  </button>
                ))}
              </div>
            </div>
          )}

          {error && <div className="text-xs text-danger">{error}</div>}
        </div>

        <DialogFooter>
          <span className="text-[11px] text-muted-foreground mr-auto self-center">
            {ok ? t('spm.spotSent') : targetName ? `→ ${targetName}` : t('spm.masterCluster')}
          </span>
          <Button variant="outline" onClick={onClose} disabled={busy}>{t('spm.cancel')}</Button>
          <Button onClick={send} disabled={busy}>
            {busy ? <Loader2 className="size-3.5 animate-spin" /> : <Satellite className="size-3.5" />}
            {busy ? t('spm.sending') : t('spm.sendSpot')}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

// trimKHz formats a kHz value without a trailing ".0" (14205) but keeps
// sub-kHz precision when present (10138.7).
function trimKHz(khz: number): string {
  return String(Math.round(khz * 10) / 10).replace(/\.0$/, '');
}
