// Bluetooth connection panel
function BluetoothPanel({ connected, connecting, onConnect, onDisconnect, cubeState, activeCube, onManageCubes }) {
  return (
    <div style={btStyles.panel}>
      <div style={btStyles.left}>
        <div style={{...btStyles.indicator, background: connected ? 'oklch(65% 0.18 165)' : connecting ? 'oklch(65% 0.18 80)' : 'oklch(38% 0.01 250)'}} />
        <span style={btStyles.label}>
          {connected ? `GAN Cube` : connecting ? 'Connecting…' : 'No cube'}
        </span>
        {activeCube && (
          <span style={btStyles.sub}>· {activeCube.name}</span>
        )}
        {connected && cubeState && (
          <span style={btStyles.sub}>· {cubeState.solved ? 'Solved' : 'Scrambled'}</span>
        )}
      </div>
      <div style={btStyles.actions}>
        {!activeCube && (
          <button style={btStyles.manageBtn} onClick={onManageCubes}>Add cube MAC</button>
        )}
        <button
          style={{...btStyles.btn, ...(connected ? btStyles.btnDisconnect : {})}}
          onClick={connected ? onDisconnect : onConnect}
          disabled={connecting}
        >
          {connected ? 'Disconnect' : connecting ? 'Connecting…' : '⬡ Connect GAN'}
        </button>
      </div>
    </div>
  );
}

const btStyles = {
  panel: {
    display: 'flex', alignItems: 'center', justifyContent: 'space-between',
    padding: '10px 16px',
    background: 'oklch(14% 0.01 250)',
    border: '1px solid oklch(20% 0.01 250)',
    borderRadius: '8px',
  },
  left: { display: 'flex', alignItems: 'center', gap: '8px' },
  indicator: { width: '8px', height: '8px', borderRadius: '50%' },
  label: { fontSize: '13px', color: 'oklch(70% 0.01 250)', fontFamily: "'JetBrains Mono', monospace" },
  sub: { fontSize: '12px', color: 'oklch(45% 0.01 250)' },
  actions: { display: 'flex', alignItems: 'center', gap: '8px' },
  manageBtn: {
    padding: '6px 10px', borderRadius: '6px', border: '1px solid oklch(30% 0.08 165)',
    background: 'transparent', color: 'oklch(65% 0.14 165)',
    fontSize: '12px', cursor: 'pointer', fontFamily: "'Inter', sans-serif",
  },
  btn: {
    padding: '6px 14px', borderRadius: '6px', border: '1px solid oklch(30% 0.01 250)',
    background: 'oklch(18% 0.01 250)', color: 'oklch(75% 0.01 250)',
    fontSize: '12px', cursor: 'pointer', fontFamily: "'Inter', sans-serif",
    fontWeight: '500', transition: 'all 0.15s',
  },
  btnDisconnect: {
    border: '1px solid oklch(30% 0.12 25)',
    color: 'oklch(65% 0.12 25)',
  },
};

// Scramble display
function ScrambleDisplay({ scramble, loading, onNew }) {
  const moves = scramble ? scramble.split(' ') : [];
  return (
    <div style={scrStyles.wrap}>
      <div style={scrStyles.movesRow}>
        {loading ? (
          <span style={scrStyles.loading}>Generating…</span>
        ) : (
          moves.map((m, i) => (
            <span key={i} style={{
              ...scrStyles.move,
              ...(m.includes("'") ? scrStyles.prime : {}),
              ...(m.includes('2') ? scrStyles.double : {}),
            }}>{m}</span>
          ))
        )}
      </div>
      <button style={scrStyles.newBtn} onClick={onNew} title="New scramble (n)">↺ New</button>
    </div>
  );
}

const scrStyles = {
  wrap: {
    display: 'flex', alignItems: 'flex-start', gap: '16px',
    background: 'oklch(14% 0.01 250)',
    border: '1px solid oklch(20% 0.01 250)',
    borderRadius: '8px', padding: '16px 20px',
  },
  movesRow: {
    flex: 1, display: 'flex', flexWrap: 'wrap', gap: '4px 2px', alignItems: 'baseline',
  },
  move: {
    fontFamily: "'JetBrains Mono', monospace",
    fontSize: '17px', fontWeight: '500',
    color: 'oklch(85% 0.01 250)',
    padding: '2px 5px', borderRadius: '4px',
    letterSpacing: '0.02em',
  },
  prime: { color: 'oklch(75% 0.14 165)' },
  double: { color: 'oklch(75% 0.10 200)' },
  loading: { color: 'oklch(45% 0.01 250)', fontFamily: "'JetBrains Mono', monospace", fontSize: '15px' },
  newBtn: {
    padding: '6px 12px', borderRadius: '6px',
    border: '1px solid oklch(25% 0.01 250)',
    background: 'oklch(18% 0.01 250)',
    color: 'oklch(55% 0.01 250)', fontSize: '12px',
    cursor: 'pointer', fontFamily: "'Inter', sans-serif",
    whiteSpace: 'nowrap', flexShrink: 0,
    transition: 'all 0.15s',
  },
};

// The main stackmat-style timer
function Timer({ onSolveComplete, cubeConnected }) {
  // States: idle | ready | memo | executing | stopped
  const [phase, setPhase] = React.useState('idle');
  const [display, setDisplay] = React.useState(0);
  const [memoTime, setMemoTime] = React.useState(null);
  const [execTime, setExecTime] = React.useState(null);
  const [penalty, setPenalty] = React.useState(null); // null | 'plus2' | 'dnf'

  const startRef = React.useRef(null);
  const memoSplitRef = React.useRef(null);
  const spaceDownRef = React.useRef(false);
  const holdTimerRef = React.useRef(null);
  const rafRef = React.useRef(null);
  const phaseRef = React.useRef('idle');

  // Keep phaseRef in sync
  React.useEffect(() => { phaseRef.current = phase; }, [phase]);

  // Tick
  React.useEffect(() => {
    if (phase === 'memo' || phase === 'executing') {
      const tick = () => {
        setDisplay(Date.now() - startRef.current);
        rafRef.current = requestAnimationFrame(tick);
      };
      rafRef.current = requestAnimationFrame(tick);
      return () => cancelAnimationFrame(rafRef.current);
    }
  }, [phase]);

  function startSolve() {
    startRef.current = Date.now();
    memoSplitRef.current = null;
    setMemoTime(null);
    setExecTime(null);
    setPenalty(null);
    setDisplay(0);
    setPhase('memo');
  }

  function splitMemo() {
    if (phaseRef.current !== 'memo') return;
    memoSplitRef.current = Date.now();
    setMemoTime(memoSplitRef.current - startRef.current);
    setPhase('executing');
  }

  function stopTimer() {
    const now = Date.now();
    const total = now - startRef.current;
    const memo = memoSplitRef.current ? memoSplitRef.current - startRef.current : null;
    const exec = memo !== null ? total - memo : total;
    setMemoTime(memo);
    setExecTime(exec);
    setDisplay(total);
    setPhase('stopped');
    return { total, memo, exec };
  }

  // Keyboard handling — stackmat style
  React.useEffect(() => {
    function onKeyDown(e) {
      if (e.repeat) return;
      const p = phaseRef.current;

      if (e.code === 'Space') {
        e.preventDefault();
        if (p === 'idle' || p === 'stopped') {
          if (!spaceDownRef.current) {
            spaceDownRef.current = true;
            holdTimerRef.current = setTimeout(() => {
              setPhase('ready');
            }, 300);
          }
        } else if (p === 'memo') {
          // Split to executing
          splitMemo();
        } else if (p === 'executing') {
          // Stop
          stopTimer();
        }
      }

      if (e.code === 'KeyN' && (p === 'idle' || p === 'stopped')) {
        window._onNewScramble && window._onNewScramble();
      }
    }

    function onKeyUp(e) {
      if (e.code === 'Space') {
        e.preventDefault();
        clearTimeout(holdTimerRef.current);
        const p = phaseRef.current;
        if (p === 'ready') {
          // Held long enough — start
          startSolve();
        }
        spaceDownRef.current = false;
      }
    }

    window.addEventListener('keydown', onKeyDown);
    window.addEventListener('keyup', onKeyUp);
    return () => {
      window.removeEventListener('keydown', onKeyDown);
      window.removeEventListener('keyup', onKeyUp);
    };
  }, []);

  // When stopped — emit solve
  const emittedRef = React.useRef(false);
  React.useEffect(() => {
    if (phase === 'stopped' && !emittedRef.current && memoTime !== null && execTime !== null) {
      emittedRef.current = true;
    }
    if (phase !== 'stopped') emittedRef.current = false;
  }, [phase, memoTime, execTime]);

  function applyPenalty(p) {
    setPenalty(p);
    const total = display;
    const memo = memoTime;
    const exec = execTime;
    onSolveComplete({ total, memo, exec, dnf: p === 'dnf', plusTwo: p === 'plus2' });
    setPhase('idle');
  }

  function discardSolve() {
    setPhase('idle');
    setPenalty(null);
  }

  // Color for timer display
  const timerColor = phase === 'ready' ? 'oklch(65% 0.18 165)'
    : phase === 'memo' ? 'oklch(75% 0.14 80)'
    : phase === 'executing' ? 'oklch(85% 0.01 250)'
    : phase === 'stopped' ? 'oklch(65% 0.14 165)'
    : 'oklch(38% 0.01 250)';

  const showMs = phase === 'executing' || phase === 'memo';

  return (
    <div style={timerStyles.wrap}>
      {/* Phase label */}
      <div style={timerStyles.phaseRow}>
        <span style={{...timerStyles.phaseChip, ...phaseChipStyle(phase)}}>
          {phaseLabel(phase)}
        </span>
        {phase === 'memo' && (
          <span style={timerStyles.hint}>Space = first move done · Cube move (BT) = auto-split</span>
        )}
        {phase === 'executing' && (
          <span style={timerStyles.hint}>Space = stop</span>
        )}
        {(phase === 'idle' || phase === 'stopped') && phase !== 'stopped' && (
          <span style={timerStyles.hint}>Hold Space to ready</span>
        )}
      </div>

      {/* Main display */}
      <div style={{...timerStyles.display, color: timerColor}}>
        {phase === 'ready' ? (
          <span style={timerStyles.readyDot}>●</span>
        ) : (
          formatTime(display)
        )}
      </div>

      {/* Split row (memo / exec) */}
      {(phase === 'executing' || phase === 'stopped') && memoTime !== null && (
        <div style={timerStyles.splitRow}>
          <div style={timerStyles.split}>
            <span style={timerStyles.splitLabel}>MEMO</span>
            <span style={timerStyles.splitVal}>{formatTime(memoTime)}</span>
          </div>
          <div style={timerStyles.splitDivider} />
          <div style={timerStyles.split}>
            <span style={timerStyles.splitLabel}>EXEC</span>
            <span style={timerStyles.splitVal}>{phase === 'stopped' ? formatTime(execTime) : formatTime(display - memoTime)}</span>
          </div>
        </div>
      )}

      {/* Post-solve actions */}
      {phase === 'stopped' && (
        <div style={timerStyles.actions}>
          <button style={{...timerStyles.actionBtn, ...timerStyles.actionOk}}
            onClick={() => applyPenalty(null)}>✓ OK</button>
          <button style={{...timerStyles.actionBtn, ...timerStyles.actionPlus2}}
            onClick={() => applyPenalty('plus2')}>+2</button>
          <button style={{...timerStyles.actionBtn, ...timerStyles.actionDnf}}
            onClick={() => applyPenalty('dnf')}>DNF</button>
          <button style={{...timerStyles.actionBtn, ...timerStyles.actionDiscard}}
            onClick={discardSolve}>✕ Discard</button>
        </div>
      )}
    </div>
  );
}

function phaseLabel(phase) {
  return { idle: 'IDLE', ready: 'READY', memo: 'MEMO', executing: 'EXEC', stopped: 'DONE' }[phase] || phase.toUpperCase();
}
function phaseChipStyle(phase) {
  const map = {
    idle:      { background: 'oklch(18% 0.01 250)', color: 'oklch(45% 0.01 250)' },
    ready:     { background: 'oklch(20% 0.16 165)', color: 'oklch(65% 0.18 165)' },
    memo:      { background: 'oklch(20% 0.12 80)',  color: 'oklch(70% 0.18 80)'  },
    executing: { background: 'oklch(18% 0.08 200)', color: 'oklch(70% 0.12 200)' },
    stopped:   { background: 'oklch(20% 0.12 165)', color: 'oklch(65% 0.18 165)' },
  };
  return map[phase] || {};
}

const timerStyles = {
  wrap: {
    display: 'flex', flexDirection: 'column', alignItems: 'center',
    gap: '16px', padding: '32px 24px',
    background: 'oklch(14% 0.01 250)',
    border: '1px solid oklch(20% 0.01 250)',
    borderRadius: '8px',
  },
  phaseRow: { display: 'flex', alignItems: 'center', gap: '12px', height: '24px' },
  phaseChip: {
    fontFamily: "'JetBrains Mono', monospace",
    fontSize: '11px', fontWeight: '700', letterSpacing: '0.12em',
    padding: '3px 8px', borderRadius: '4px',
  },
  hint: { fontSize: '12px', color: 'oklch(40% 0.01 250)' },
  display: {
    fontFamily: "'JetBrains Mono', monospace",
    fontSize: '88px', fontWeight: '300', letterSpacing: '-3px',
    lineHeight: 1, transition: 'color 0.2s',
    minWidth: '360px', textAlign: 'center',
  },
  readyDot: { fontSize: '48px', letterSpacing: 0 },
  splitRow: {
    display: 'flex', alignItems: 'center', gap: '24px',
  },
  split: { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '4px' },
  splitLabel: {
    fontFamily: "'JetBrains Mono', monospace",
    fontSize: '10px', letterSpacing: '0.12em', color: 'oklch(40% 0.01 250)',
  },
  splitVal: {
    fontFamily: "'JetBrains Mono', monospace",
    fontSize: '22px', fontWeight: '400', color: 'oklch(70% 0.01 250)',
  },
  splitDivider: { width: '1px', height: '36px', background: 'oklch(22% 0.01 250)' },
  actions: { display: 'flex', gap: '8px', marginTop: '4px' },
  actionBtn: {
    padding: '9px 20px', borderRadius: '8px', border: 'none',
    fontSize: '13px', fontWeight: '600', cursor: 'pointer',
    fontFamily: "'Inter', sans-serif", transition: 'opacity 0.15s',
  },
  actionOk:      { background: 'oklch(65% 0.18 165)', color: 'oklch(10% 0.01 250)' },
  actionPlus2:   { background: 'oklch(22% 0.01 250)', color: 'oklch(65% 0.14 80)', border: '1px solid oklch(30% 0.08 80)' },
  actionDnf:     { background: 'oklch(22% 0.01 250)', color: 'oklch(65% 0.14 25)', border: '1px solid oklch(30% 0.08 25)' },
  actionDiscard: { background: 'transparent', color: 'oklch(40% 0.01 250)', border: '1px solid oklch(22% 0.01 250)' },
};

Object.assign(window, { Timer, BluetoothPanel, ScrambleDisplay });
