import React, { useState } from 'react';
import { num, systemAlerts } from '../api/useXplane.js';

// The physical GDU bezel of X-Plane's "XPLANE 1000" (its G1000 clone):
// title bar, knob columns, the 12 softkeys along the bottom — and, on the MFD,
// the autopilot mode controller built into the left bezel (just like the sim).
//
// EVERY control is clickable and fires the matching real X-Plane command
// (sim/GPS/g1000n1_* on the PFD, g1000n3_* on the MFD) via xp.command().
//
// The PFD softkeys are a two-level menu, exactly like the real unit:
//  root → [INSET · PFD · CDI · DME · XPDR · IDENT · TMR/REF · NRST · CAUTION]
//  PFD  → [PATHWAY · SYN TERR · HRZN HDG · APTSIGNS · … · BACK]
// SYN TERR toggles the 3D synthetic-vision terrain on/off.
const PFD_MENU = {
  root: ['', 'INSET', '', 'PFD', '', 'CDI', 'DME', 'XPDR', 'IDENT', 'TMR/REF', 'NRST', 'CAUTION'],
  pfd:  ['PATHWAY', 'SYN TERR', 'HRZN HDG', 'APTSIGNS', 'ALT UNIT', '', '', '', '', '', '', 'BACK'],
  // ALT UNIT submenu: barometric pressure units (inHg / hectopascal), like the manual.
  altunit: ['IN', 'HPA', '', '', '', '', '', '', '', '', '', 'BACK'],
  // XPDR submenu: standby/on/alt modes, VFR (1200), CODE entry, IDENT.
  xpdr: ['STBY', 'ON', 'ALT', 'VFR', '', 'CODE', 'IDENT', '', '', '', '', 'BACK'],
  // CODE entry turns the softkeys into the octal squawk keypad (digits 0–7).
  xpdrcode: ['0', '1', '2', '3', '4', '5', '6', '7', 'BKSP', '', 'BACK', ''],
  // INSET submenu: on/off, declutter, base layer, OFF, back.
  inset: ['INSET', 'DCLTR', '', 'TOPO', 'TERRAIN', '', '', '', '', '', 'OFF', 'BACK'],
};
// MFD softkeys are a two-level menu like the real unit. MAP opens the Map-Opt
// page; TOPO/TERRAIN/OSM switch the base map; BACK returns. (OSM is our tuned
// extra layer in an otherwise-empty slot.)
const MFD_MENU = {
  root:   ['ENGINE', 'MAP', '', '', '', '', '', '', '', 'DCLTR', '', ''],
  mapopt: ['TRAFFIC', 'PROFILE', 'TOPO', 'TERRAIN', 'AIRWAYS', '', 'NEXRAD', 'OSM', '', '', 'BACK', ''],
  engine: ['DEC FUEL', 'INC FUEL', 'RST FUEL', '', '', '', '', '', '', '', 'BACK', ''],
};

// autopilot_state bitfield (best-effort; tweak per aircraft)
const AP_BITS = { fd: 1 << 0, hdg: 1 << 1, vs: 1 << 4, flc: 1 << 6, nav: 1 << 8, apr: 1 << 9, vnav: 1 << 11, altHold: 1 << 14, bc: 1 << 18 };

export default function Bezel({ variant = 'pfd', xp, svt3d, onToggleSvt, inset, onSetInset, insetMode, onInsetMode, nrst, onToggleNrst, tmr, onToggleTmr, dme, onToggleDme, alerts, onToggleAlerts, onDirect, onProc, onFpl, onClr, onFms, mapMode, onMapMode, altHpa, onAltUnit, obs, onObs, knobMode = 'arrows', children }) {
  const u = variant === 'mfd' ? 'mfd' : 'pfd';           // command prefix
  const fire = (suffix) => xp && xp.command(`${u}_${suffix}`);
  const [page, setPage] = useState('root');              // softkey menu page
  const [squawk, setSquawk] = useState('');              // XPDR code being typed

  const menu = variant === 'mfd' ? MFD_MENU : PFD_MENU;
  let keys = menu[page] || menu.root;
  // OBS appears in the PFD root only when a flight-plan leg is active (like the real unit)
  const hasLeg = (xp?.flightPlan?.waypoints?.length || 0) >= 2;
  if (variant !== 'mfd' && page === 'root' && hasLeg) { keys = keys.slice(); keys[4] = 'OBS'; }
  const setBase = (b) => onMapMode && onMapMode((m) => ({ ...m, base: m.base === b ? 'dark' : b }));
  const xpdrMode = num(xp?.values?.xpdrMode);
  const setMode = (m) => xp && xp.setDataref('xpdrMode', m);
  const hasAlerts = systemAlerts(xp?.values).length > 0;   // lights the CAUTION key

  const typeDigit = (d) => {
    const next = (squawk + d).slice(-4);
    setSquawk(next);
    if (next.length === 4) {                             // 4 octal digits → write & exit
      xp && xp.setDataref('xpdrCode', parseInt(next, 10));
      setSquawk(''); setPage('xpdr');
    }
  };

  const onSoftkey = (i, label) => {
    fire(`softkey${i + 1}`);                             // mirror to the in-sim G1000
    // declutter cycles through 4 levels (0=all … 3=flight plan only), like the manual
    const cycleDcltr = (setter) => setter && setter((m) => ({ ...m, dcltr: (((m.dcltr || 0) + 1) % 4) }));
    if (variant === 'mfd') {
      if (label === 'MAP') setPage('mapopt');
      else if (label === 'ENGINE') setPage('engine');
      else if (label === 'BACK') setPage('root');
      else if (label === 'TOPO') setBase('topo');                                         // relief on/off
      else if (label === 'TERRAIN') onMapMode && onMapMode((m) => ({ ...m, terrain: !m.terrain })); // awareness overlay (independent)
      else if (label === 'OSM') setBase('osm');
      else if (label === 'DCLTR') cycleDcltr(onMapMode);
      else if (label === 'AIRWAYS') onMapMode && onMapMode((m) => ({ ...m, airways: !m.airways }));
    } else {
      if (label === 'PFD') setPage('pfd');
      else if (label === 'BACK') setPage({ xpdrcode: 'xpdr', altunit: 'pfd' }[page] || 'root');
      else if (label === 'SYN TERR') onToggleSvt && onToggleSvt();
      else if (label === 'ALT UNIT') setPage('altunit');
      else if (label === 'IN') { onAltUnit && onAltUnit(false); setPage('pfd'); }
      else if (label === 'HPA') { onAltUnit && onAltUnit(true); setPage('pfd'); }
      else if (label === 'INSET') {
        if (page === 'root') { onSetInset && onSetInset(true); setPage('inset'); }
        else onSetInset && onSetInset(!inset);          // toggle from within the submenu
      }
      else if (label === 'OFF') { onSetInset && onSetInset(false); setPage('root'); }
      else if (label === 'DCLTR') cycleDcltr(onInsetMode);
      else if (label === 'TOPO') onInsetMode && onInsetMode((m) => ({ ...m, base: m.base === 'topo' ? 'dark' : 'topo' }));
      else if (label === 'TERRAIN') onInsetMode && onInsetMode((m) => ({ ...m, terrain: !m.terrain }));
      else if (label === 'NRST') onToggleNrst && onToggleNrst();
      else if (label === 'TMR/REF') onToggleTmr && onToggleTmr();
      else if (label === 'DME') onToggleDme && onToggleDme();
      else if (label === 'OBS') onObs && onObs();   // suspend / OBS mode (also fires the sim softkey above)
      else if (label === 'CAUTION') onToggleAlerts && onToggleAlerts();
      else if (label === 'XPDR') setPage('xpdr');
      else if (label === 'STBY') setMode(1);
      else if (label === 'ON') setMode(2);
      else if (label === 'ALT') setMode(3);
      else if (label === 'VFR') xp && xp.setDataref('xpdrCode', 1200);
      else if (label === 'CODE') { setSquawk(''); setPage('xpdrcode'); }
      else if (label === 'IDENT') xp && xp.command('xpdrIdent');
      else if (label === 'BKSP') setSquawk((s) => s.slice(0, -1));
      else if (page === 'xpdrcode' && /^[0-7]$/.test(label)) typeDigit(label);
    }
  };
  // which softkey is "lit" right now
  const isOn = (label) => {
    if (variant === 'mfd') return (label === 'TOPO' && mapMode?.base === 'topo')
      || (label === 'TERRAIN' && mapMode?.terrain) || (label === 'OSM' && mapMode?.base === 'osm')
      || (label === 'DCLTR' && mapMode?.dcltr > 0) || (label === 'AIRWAYS' && mapMode?.airways);
    return (label === 'SYN TERR' && svt3d) || (label === 'INSET' && inset) || (label === 'NRST' && nrst) || (label === 'TMR/REF' && tmr)
      || (label === 'DME' && dme) || (label === 'OBS' && obs) || (label === 'CAUTION' && (alerts || hasAlerts))
      || (label === 'STBY' && xpdrMode === 1) || (label === 'ON' && xpdrMode === 2) || (label === 'ALT' && xpdrMode === 3)
      || (label === 'IN' && !altHpa) || (label === 'HPA' && altHpa)
      || (page === 'inset' && label === 'TOPO' && insetMode?.base === 'topo')
      || (page === 'inset' && label === 'TERRAIN' && insetMode?.terrain)
      || (label === 'DCLTR' && insetMode?.dcltr > 0);
  };

  return (
    <div className="bezel">
      <div className="bezel-knobs left">
        <Knob label="NAV" sub="VOL · PUSH ID" fire={fire} mode={knobMode}
          outer={['nav_outer_up', 'nav_outer_down']} inner={['nav_inner_up', 'nav_inner_down']} push="nav12"
          swap={() => xp && xp.command('nav1Swap')} />
        <Knob label="HDG" sub="PUSH HDG SYNC" fire={fire} mode={knobMode}
          outer={['hdg_up', 'hdg_down']} push="hdg_sync" />
        {variant === 'mfd' && xp && <APController xp={xp} />}
        <Knob label="ALT" sub="" big fire={fire} mode={knobMode}
          outer={['alt_outer_up', 'alt_outer_down']} inner={['alt_inner_up', 'alt_inner_down']} />
      </div>

      <div className="bezel-core">
        <div className="bezel-title">XPLANE 1000</div>
        <div className="bezel-screen">
          <div className="screen-content">{children}</div>
          {page === 'xpdrcode' && (
            <div className="squawk-entry">SQUAWK <b>{squawk.padEnd(4, '_')}</b></div>
          )}
          {/* softkey LABELS on the display (lowest line), like the real G1000 */}
          <div className="sk-labels">
            {keys.map((s, i) => (
              <span key={i} className={`skl ${s ? '' : 'empty'} ${s === 'CAUTION' ? 'caution' : ''} ${isOn(s) ? 'on' : ''}`}>{
                (s === 'DCLTR' && (mapMode?.dcltr || insetMode?.dcltr)) ? `DCLTR-${mapMode?.dcltr || insetMode?.dcltr}` : s
              }</span>
            ))}
          </div>
        </div>
        {/* physical bezel keys — blank, aligned under the on-screen labels */}
        <div className="softkeys">
          {keys.map((s, i) => (
            <button key={i} disabled={!s} onClick={() => onSoftkey(i, s)}
              className={`softkey ${s ? '' : 'empty'}`} aria-label={s || undefined} />
          ))}
        </div>
      </div>

      <div className="bezel-knobs right">
        <Knob label="COM" sub="VOL · PUSH SQ" fire={fire} mode={knobMode}
          outer={['com_outer_up', 'com_outer_down']} inner={['com_inner_up', 'com_inner_down']} push="com12"
          swap={() => xp && xp.command('com1Swap')} emerg />
        <Knob label="CRS / BARO" sub="PUSH CRS CTR" fire={fire} mode={knobMode}
          outer={['crs_up', 'crs_down']} inner={['baro_up', 'baro_down']} push="crs_sync" />
        <Knob label="RANGE" sub="PUSH PAN" joy fire={fire} mode={knobMode}
          outer={['range_up', 'range_down']} push="pan_push" pan />
        <div className="bezel-grid">
          <BtnG fire={fire} mode={knobMode} cmd="direct" onClick={onDirect}>D→</BtnG><BtnG fire={fire} mode={knobMode} cmd="menu">MENU</BtnG>
          <BtnG fire={fire} mode={knobMode} cmd="fpl" onClick={onFpl}>FPL</BtnG><BtnG fire={fire} mode={knobMode} cmd="proc" onClick={onProc}>PROC</BtnG>
          <BtnG fire={fire} mode={knobMode} cmd="clr" onClick={onClr}>CLR</BtnG><BtnG fire={fire} mode={knobMode} cmd="ent">ENT</BtnG>
        </div>
        <Knob label="FMS" sub="PUSH CRSR" big fire={fire} mode={knobMode}
          outer={['fms_outer_up', 'fms_outer_down']} inner={['fms_inner_up', 'fms_inner_down']} push="cursor"
          onTurn={onFms} />
      </div>
    </div>
  );
}

function BtnG({ fire, cmd, onClick, children }) {
  return <button className="bezel-btn sm" onClick={() => { fire(cmd); onClick && onClick(); }}>{children}</button>;
}

// Autopilot mode controller (left bezel of the MFD). Buttons fire real X-Plane
// commands; active modes light up from autopilot_state / servos_on.
function APController({ xp }) {
  const st = num(xp.values.apState);
  const on = (bit) => (st & bit) !== 0;
  const eng = num(xp.values.apEngaged) > 0;
  const B = ({ label, cmd, active }) => (
    <button className={`ap-key ${active ? 'on' : ''}`} onClick={() => xp.command(cmd)}>{label}</button>
  );
  return (
    <div className="ap-controller">
      <B label="AP" cmd="apToggle" active={eng} />
      <B label="FD" cmd="fdToggle" active={on(AP_BITS.fd)} />
      <B label="HDG" cmd="hdg" active={on(AP_BITS.hdg)} />
      <B label="ALT" cmd="altHold" active={on(AP_BITS.altHold)} />
      <B label="NAV" cmd="nav" active={on(AP_BITS.nav)} />
      <B label="VNV" cmd="vnav" active={on(AP_BITS.vnav)} />
      <B label="APR" cmd="apr" active={on(AP_BITS.apr)} />
      <B label="BC" cmd="backCourse" active={on(AP_BITS.bc)} />
      <B label="VS" cmd="vs" active={on(AP_BITS.vs)} />
      <B label="FLC" cmd="flc" active={on(AP_BITS.flc)} />
      <B label="NOSE UP" cmd="noseUp" />
      <B label="NOSE DN" cmd="noseDown" />
    </div>
  );
}

// Concentric G1000 knob. The outer ring rotates via the side arrows (‹ ›) and
// the mouse wheel; the inner ring via the top/bottom arrows (˄ ˅) and shift+wheel.
// Clicking the knob centre fires the push action (PUSH …). The RANGE knob also
// pans with a directional cross.
function Knob({ label, sub, outer, inner, push, big, joy, pan, fire, mode = 'arrows', swap, emerg, onTurn }) {
  // turn the outer ring: fire the sim command AND notify (e.g. cycle MFD page)
  const outerStep = (dir) => { if (!outer) return; fire(dir > 0 ? outer[0] : outer[1]); if (onTurn) onTurn(dir); };
  const onWheel = (e) => {
    if (!outer) return;
    e.preventDefault();
    if (e.shiftKey && inner) fire(e.deltaY < 0 ? inner[0] : inner[1]);
    else outerStep(e.deltaY < 0 ? 1 : -1);
  };
  const zoneClick = (e) => {
    const r = e.currentTarget.getBoundingClientRect();
    const dx = e.clientX - (r.left + r.width / 2);
    const dy = e.clientY - (r.top + r.height / 2);
    const rel = Math.hypot(dx, dy) / (r.width / 2);
    if (rel < 0.42 && push) { fire(push); return; }   // centre → PUSH
    if (Math.abs(dy) >= Math.abs(dx)) outerStep(dy < 0 ? 1 : -1);
    else if (inner) fire(dx > 0 ? inner[0] : inner[1]);
    else outerStep(dx > 0 ? 1 : -1);
  };
  const zones = mode === 'zones';
  return (
    <div className={`knob-wrap ${big ? 'big' : ''}`}>
      {swap && <button className="knob-swap" onClick={swap} title="Aktiv ↔ Standby">⇆</button>}
      {emerg && <span className="knob-emerg">EMERG</span>}
      <span className="knob-lbl">{label}</span>
      <div className={`knob-cluster ${zones ? 'zones' : ''}`}>
        {/* arrows mode (touch-friendly): visible ˄‹›˅ buttons. zones mode: click
            the knob face itself (top/bottom = outer, left/right = inner). */}
        {!zones && inner && <button className="knob-arrow top" onClick={() => fire(inner[0])}>˄</button>}
        {!zones && outer && <button className="knob-arrow left" onClick={() => outerStep(-1)}>‹</button>}
        <button
          className={`knob outer ${joy ? 'joy' : ''}`}
          onWheel={onWheel}
          onClick={zones ? zoneClick : (() => push && fire(push))}
          title={zones ? `${outer ? 'oben/unten' : ''}${inner ? ' · links/rechts (fein)' : ''}${push ? ' · Mitte: PUSH' : ''}` : (push ? 'PUSH' : '')}
        >
          <span className="knob inner" />
          {joy && (<>
            <span className="rng-ring" />
            <span className="rng-arc l">↶</span>
            <span className="rng-arc r">↷</span>
            <span className="rng-sign m">–</span>
            <span className="rng-sign p">+</span>
          </>)}
        </button>
        {!zones && outer && <button className="knob-arrow right" onClick={() => outerStep(1)}>›</button>}
        {!zones && inner && <button className="knob-arrow bottom" onClick={() => fire(inner[1])}>˅</button>}
      </div>
      {pan && (
        <div className="pan-pad">
          <button onClick={() => fire('pan_up')}>▲</button>
          <button onClick={() => fire('pan_left')}>◄</button>
          <button onClick={() => fire('pan_right')}>►</button>
          <button onClick={() => fire('pan_down')}>▼</button>
        </div>
      )}
      {sub && <span className="knob-sub">{sub}</span>}
    </div>
  );
}
