import { useEffect, useState } from 'react';
import { Radio, Square, Send, Plug, Power, RefreshCw, X, ChevronUp, ChevronDown } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
  Select, SelectTrigger, SelectValue, SelectContent, SelectItem,
} from '@/components/ui/select';
import { cn } from '@/lib/utils';
import { useI18n } from '@/lib/i18n';

export interface WKMacro { label: string; text: string }
export interface WKStatus {
  connected: boolean;
  busy: boolean;
  wpm: number;
  version: number;
  port: string;
  error?: string;
}

interface Props {
  status: WKStatus;
  ports: string[];
  port: string;
  wpm: number;
  macros: WKMacro[];
  sent: string; // text echoed back by the keyer as it transmits
  source: 'winkeyer' | 'icom' | 'flex' | 'yaesu' | 'kenwood' | 'tci'; // CW output engine (chosen in Settings → CW Keyer)
  breakIn?: number;                          // Icom CW break-in: 0=OFF, 1=SEMI, 2=FULL
  onSetBreakIn?: (mode: number) => void;
  onSelectPort: (p: string) => void;
  onRefreshPorts: () => void;
  onConnect: () => void;
  onDisconnect: () => void;
  onSetSpeed: (wpm: number) => void;
  onSend: (text: string) => void;       // raw text (App resolves variables)
  onSendMacro: (index: number) => void; // App resolves the macro + sends
  onStop: () => void;
  onClose: () => void;                  // disable the keyer (hide the panel)
  sendOnType: boolean;
  onToggleSendOnType: (on: boolean) => void;
  onSendRaw: (chars: string) => void;   // key typed chars as-is (no variables)
  onBackspace: () => void;              // remove last not-yet-keyed char
  autoCall: boolean;                    // repeat the clicked macro on a timer
  autoCallSecs: number;                 // gap (s) after the message before repeating
  onToggleAutoCall: (on: boolean) => void;
  onSetAutoCallSecs: (n: number) => void;
}

// WinkeyerPanel — Log4OM-style CW keyer operating window. Lives in the
// reserved space to the right of the F1-F5 tabs. Sends Morse via the WinKeyer
// hardware: free-text CW, one-click macros (F1…), live speed, and abort.
export function WinkeyerPanel({
  status, ports, port, wpm, macros, sent, source, breakIn = 0, onSetBreakIn,
  onSelectPort, onRefreshPorts, onConnect, onDisconnect, onSetSpeed,
  onSend, onSendMacro, onStop, onClose,
  sendOnType, onToggleSendOnType, onSendRaw, onBackspace,
  autoCall, autoCallSecs, onToggleAutoCall, onSetAutoCallSecs,
}: Props) {
  const { t } = useI18n();
  const [cwText, setCwText] = useState('');
  const [speed, setSpeed] = useState(wpm);
  // Step the speed (compact +/- control replaces the old slider).
  const changeSpeed = (delta: number) => {
    const w = Math.max(5, Math.min(50, speed + delta));
    setSpeed(w);
    onSetSpeed(w);
  };

  // Keep the local speed in sync when the device/config changes it.
  useEffect(() => { setSpeed(status.connected ? status.wpm || wpm : wpm); }, [status.wpm, status.connected, wpm]);

  const connected = status.connected;

  // Send-on-type only exists where the engine can key one character at a time:
  // the WinKeyer and Flex CWX. The stored preference survives an engine change,
  // though, and an Icom or Yaesu operator inherited a hidden switch that was on
  // — the checkbox is not shown for them, so nothing keyed as they typed AND
  // Enter sent nothing either, since it believes the text has already gone.
  // Macros kept working, which is exactly how it looked from the outside.
  const liveType = sendOnType && (source === 'winkeyer' || source === 'flex');

  function sendText() {
    const t = cwText.trim();
    if (t && !liveType) onSend(t); // in send-on-type the text already went out
    setCwText('');
  }

  // In "send on type" mode, key each newly-typed char immediately, and send a
  // WinKeyer backspace for each deleted char (removes it from the buffer if it
  // hasn't been keyed yet). Only end-of-string edits are mirrored live.
  function onCwChange(v: string) {
    if (liveType && connected) {
      const old = cwText;
      if (v.length > old.length && v.startsWith(old)) {
        onSendRaw(v.slice(old.length));
      } else if (v.length < old.length && old.startsWith(v)) {
        for (let i = 0; i < old.length - v.length; i++) onBackspace();
      }
    }
    setCwText(v);
  }

  return (
    <section className="flex flex-col gap-2 h-full min-h-0 rounded-lg border border-border bg-card overflow-hidden">
      {/* Header / connection bar */}
      <div className="flex items-center gap-2 px-3 py-1.5 bg-muted/40 border-b border-border shrink-0">
        <Radio className="size-4 text-primary shrink-0" />
        {/* CW output engine (chosen in Settings → CW Keyer). */}
        <span className="text-xs font-semibold uppercase tracking-wider text-muted-foreground shrink-0">
          {source === 'icom' ? 'Icom CW' : source === 'flex' ? 'Flex CWX' : source === 'yaesu' ? 'Yaesu CW' : source === 'kenwood' ? 'Kenwood CW' : source === 'tci' ? 'TCI CW' : 'WinKeyer'}
        </span>
        <span className={cn('size-2 rounded-full', connected ? (status.busy ? 'bg-warning animate-pulse' : 'bg-success') : 'bg-muted-foreground/40')}
          title={connected ? (status.busy ? t('wkp.sending') : t('wkp.connectedV', { version: status.version })) : t('wkp.disconnected')} />
        <div className="flex-1" />
        {source === 'icom' || source === 'flex' || source === 'yaesu' || source === 'kenwood' || source === 'tci' ? (
          <span className="text-[11px] font-medium text-muted-foreground">
            {source === 'flex'
              ? (connected ? t('wkp.cwxReady') : t('wkp.cwxOffline'))
              : source === 'yaesu' || source === 'kenwood' || source === 'tci'
                ? (connected ? t('wkp.rigReady') : t('wkp.rigOffline'))
                : (connected ? t('wkp.civReady') : t('wkp.civOffline'))}
          </span>
        ) : !connected ? (
          <>
            <Select value={port || '_'} onValueChange={(v) => onSelectPort(v === '_' ? '' : v)}>
              <SelectTrigger className="h-7 w-28 text-xs"><SelectValue placeholder={t('wkp.comPort')} /></SelectTrigger>
              <SelectContent>
                {ports.length === 0 && <SelectItem value="_" disabled>{t('wkp.noPorts')}</SelectItem>}
                {ports.map((p) => <SelectItem key={p} value={p}>{p}</SelectItem>)}
              </SelectContent>
            </Select>
            <Button variant="ghost" size="sm" className="h-7 px-1.5" title={t('wkp.refreshPorts')} onClick={onRefreshPorts}>
              <RefreshCw className="size-3.5" />
            </Button>
            <Button size="sm" className="h-7" onClick={onConnect} disabled={!port}>
              <Plug className="size-3.5" /> {t('wkp.connect')}
            </Button>
          </>
        ) : (
          <Button variant="outline" size="sm" className="h-7" onClick={onDisconnect}>
            <Power className="size-3.5" /> {t('wkp.disconnect')}
          </Button>
        )}
        <Button variant="ghost" size="sm" className="h-7 px-1.5" title={t('wkp.hide')} onClick={onClose}>
          <X className="size-3.5" />
        </Button>
      </div>

      <div className="flex flex-col gap-1.5 px-3 pb-2 min-h-0 overflow-y-auto">
        {/* Live transmitted text (echoed by the keyer) + compact speed stepper. */}
        <div className="flex items-center gap-2">
          <Label className="text-xs w-8 shrink-0">TX</Label>
          <div className={cn(
            'flex-1 min-w-0 h-8 rounded-md border border-border bg-muted/30 px-2.5 flex items-center font-mono text-sm tracking-wide truncate',
            status.busy ? 'text-success' : 'text-muted-foreground',
          )}>
            {sent || <span className="opacity-50">—</span>}
            {status.busy && <span className="ml-0.5 animate-pulse">▌</span>}
          </div>
          {/* Speed: number + up/down arrows (replaces the slider, saves height). */}
          <div className="flex items-center gap-1 shrink-0 h-8 rounded-md border border-border bg-muted/20 pl-2 pr-1" title={t('wkp.cwSpeed')}>
            <span className="font-mono text-sm font-bold tabular-nums">{speed}</span>
            <span className="text-[9px] text-muted-foreground">wpm</span>
            <div className="flex flex-col -my-0.5">
              <button type="button" disabled={!connected} onClick={() => changeSpeed(+1)} title={t('wkp.faster')}
                className="text-muted-foreground hover:text-foreground leading-none disabled:opacity-40"><ChevronUp className="size-3.5" /></button>
              <button type="button" disabled={!connected} onClick={() => changeSpeed(-1)} title={t('wkp.slower')}
                className="text-muted-foreground hover:text-foreground leading-none disabled:opacity-40"><ChevronDown className="size-3.5" /></button>
            </div>
          </div>
        </div>

        {/* Break-in (Icom only): the rig's 0x17 keyer only transmits when break-in
            is on — SEMI or FULL. OFF keys the sidetone but stays in RX. */}
        {source === 'icom' && (
          <div className="flex items-center gap-2">
            <Label className="text-xs w-16 shrink-0" title={t('wkp.breakInHint')}>{t('wkp.breakIn')}</Label>
            <div className="inline-flex rounded-md border border-border overflow-hidden">
              {[{ v: 0, l: t('wkp.bkOff') }, { v: 1, l: 'SEMI' }, { v: 2, l: 'FULL' }].map((o) => (
                <button key={o.v} type="button" disabled={!connected} onClick={() => onSetBreakIn?.(o.v)}
                  className={cn('px-2.5 py-1 text-[11px] font-bold tracking-wide border-l border-border first:border-l-0 transition-colors disabled:opacity-40',
                    breakIn === o.v ? 'bg-primary text-primary-foreground' : 'bg-card text-muted-foreground hover:bg-muted')}>
                  {o.l}
                </button>
              ))}
            </div>
            {breakIn === 0 && <span className="text-[10px] text-warning">{t('wkp.bkOffWarn')}</span>}
          </div>
        )}

        {/* CW text */}
        <div className="flex items-end gap-2">
          <div className="flex flex-col flex-1 min-w-0">
            <Label className="mb-1 h-3.5 text-xs flex items-center gap-2">
              {t('wkp.cwText')}
              {(source === 'winkeyer' || source === 'flex') && (
                <label className="flex items-center gap-1 text-[10px] font-normal cursor-pointer text-muted-foreground"
                  title={t('wkp.sendOnTypeHint')}>
                  <input type="checkbox" className="accent-primary" checked={sendOnType}
                    onChange={(e) => onToggleSendOnType(e.target.checked)} />
                  {t('wkp.sendOnType')}
                </label>
              )}
            </Label>
            <Input
              value={cwText}
              onChange={(e) => onCwChange(e.target.value)}
              onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); sendText(); } }}
              placeholder={liveType ? t('wkp.phLive') : t('wkp.phEnter')}
              disabled={!connected}
              className="font-mono uppercase"
            />
          </div>
          <Button size="sm" className="h-8" onClick={sendText} disabled={!connected}>
            <Send className="size-3.5" /> {liveType ? t('wkp.clear') : t('wkp.send')}
          </Button>
          <Button variant="destructive" size="sm" className="h-8" onClick={onStop} disabled={!connected} title={t('wkp.abort')}>
            <Square className="size-3.5" /> {t('wkp.stop')}
          </Button>
        </div>

        {/* Auto-call: repeat the clicked macro (e.g. F1 CQ) automatically until
            someone answers. The seconds box is the gap AFTER the message. */}
        <div className="flex items-center gap-2">
          <label className="flex items-center gap-1.5 text-xs cursor-pointer select-none"
            title={t('wkp.autoCallHint')}>
            <input type="checkbox" className="accent-primary" checked={autoCall} disabled={!connected}
              onChange={(e) => onToggleAutoCall(e.target.checked)} />
            {t('wkp.autoCall')}
          </label>
          <span className="text-[11px] text-muted-foreground">{t('wkp.gap')}</span>
          <div className="flex items-center gap-1 h-7 rounded-md border border-border bg-muted/20 pl-2 pr-1" title={t('wkp.gapHint')}>
            <input type="number" min={0} max={120}
              className="w-9 bg-transparent text-sm font-mono font-bold tabular-nums text-right outline-none"
              value={autoCallSecs} onChange={(e) => onSetAutoCallSecs(parseInt(e.target.value) || 0)} />
            <span className="text-[9px] text-muted-foreground">sec</span>
          </div>
          {autoCall && <span className="text-[10px] text-warning/80">{t('wkp.loopHint')}</span>}
        </div>

        {/* Macro buttons F1… — single-line (F-key + label) to keep the panel short.
            Empty macros (no label AND no text) are hidden, like the voice keyer;
            the F-number stays tied to the macro's real index so shortcuts match. */}
        <div className="grid grid-cols-3 gap-1">
          {macros
            .map((m, i) => ({ m, i }))
            .filter(({ m }) => `${m.label ?? ''}${m.text ?? ''}`.trim() !== '')
            .map(({ m, i }) => (
            <button
              key={i}
              type="button"
              onClick={() => onSendMacro(i)}
              disabled={!connected}
              title={m.text}
              className={cn(
                'flex items-center gap-1.5 rounded-md border border-border px-2 py-1 text-left transition-colors',
                connected ? 'hover:border-primary/60 hover:bg-accent/40' : 'opacity-50 cursor-not-allowed',
              )}
            >
              <span className="text-[10px] font-mono text-primary font-semibold shrink-0">F{i + 1}</span>
              <span className="text-xs font-medium truncate">{m.label || t('wkp.macroN', { n: i + 1 })}</span>
            </button>
          ))}
        </div>
        {status.error && <div className="text-[11px] text-danger">{status.error}</div>}
      </div>
    </section>
  );
}
