/**
 * DEVKIT — HTML overlay panel with diagnostics + macro recorder + export.
 *
 * Tabs: Inputs · Cena · XR · Macro · Logs
 * Export: snapshot JSON + canvas screenshot, both downloaded.
 */
import { useEffect, useRef, useState } from 'react';
import { fakeInput, isFakeActive } from './fakeInputStore';
import { sceneStats } from './sceneStatsStore';
import {
  macroState, subscribeMacro, startRecording, stopRecording,
  startPlaying, stopPlaying, downloadMacro, loadMacroFromFile,
} from './macroStore';

interface LogEntry { ts: number; level: 'log' | 'warn' | 'error'; msg: string; }

const logBuffer: LogEntry[] = [];
let installed = false;
function installLogger() {
  if (installed) return;
  installed = true;
  (['log', 'warn', 'error'] as const).forEach((level) => {
    const orig = console[level].bind(console);
    console[level] = (...args: unknown[]) => {
      try {
        const msg = args.map((a) => {
          if (typeof a === 'string') return a;
          try { return JSON.stringify(a); } catch { return String(a); }
        }).join(' ');
        logBuffer.push({ ts: Date.now(), level, msg });
        if (logBuffer.length > 200) logBuffer.shift();
      } catch { /* noop */ }
      orig(...args);
    };
  });
}

type Tab = 'inputs' | 'cena' | 'xr' | 'macro' | 'logs';

interface DevPanelProps {
  simXR: boolean;
  onToggleSimXR: () => void;
}

export function DevPanel({ simXR, onToggleSimXR }: DevPanelProps) {
  const [tab, setTab] = useState<Tab>('inputs');
  const [collapsed, setCollapsed] = useState(false);
  const [, tick] = useState(0);
  const [logFilter, setLogFilter] = useState('');
  const fileRef = useRef<HTMLInputElement>(null);
  const rafRef = useRef<number | null>(null);

  useEffect(() => { installLogger(); }, []);
  useEffect(() => subscribeMacro(() => tick((n) => n + 1)), []);

  useEffect(() => {
    let last = 0;
    const loop = (t: number) => {
      if (t - last > 150) { tick((n) => n + 1); last = t; }
      rafRef.current = requestAnimationFrame(loop);
    };
    rafRef.current = requestAnimationFrame(loop);
    return () => { if (rafRef.current) cancelAnimationFrame(rafRef.current); };
  }, []);

  const exportReport = async () => {
    const canvas = document.querySelector('canvas');
    const screenshot = canvas ? canvas.toDataURL('image/png') : null;
    const report = {
      ts: new Date().toISOString(),
      url: window.location.href,
      userAgent: navigator.userAgent,
      simXR,
      fakeActive: isFakeActive(),
      stats: { ...sceneStats },
      inputs: {
        left: { grip: fakeInput.left.gripValue, trigger: fakeInput.left.triggerValue },
        right: { grip: fakeInput.right.gripValue, trigger: fakeInput.right.triggerValue },
      },
      logs: logBuffer.slice(-100),
    };
    const blob = new Blob([JSON.stringify(report, null, 2)], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url; a.download = `devkit-report-${Date.now()}.json`; a.click();
    URL.revokeObjectURL(url);
    if (screenshot) {
      const a2 = document.createElement('a');
      a2.href = screenshot; a2.download = `devkit-screenshot-${Date.now()}.png`; a2.click();
    }
  };

  if (collapsed) {
    return (
      <button
        onClick={() => setCollapsed(false)}
        className="fixed top-20 right-2 z-50 rounded bg-black/85 px-2 py-1 font-mono text-[10px] text-green-400 border border-green-500/40 hover:bg-black"
      >
        🧪 DevKit
      </button>
    );
  }

  return (
    <div className="fixed top-20 right-2 z-50 w-80 rounded-lg border border-green-500/40 bg-black/90 font-mono text-[10px] text-green-300 shadow-2xl backdrop-blur">
      <div className="flex items-center justify-between border-b border-green-500/30 px-2 py-1.5">
        <span className="font-bold text-green-400">🧪 DEVKIT</span>
        <div className="flex items-center gap-1">
          <button
            onClick={exportReport}
            className="rounded border border-green-500/40 px-1.5 py-0.5 text-[9px] text-green-300 hover:bg-green-500/20"
            title="Baixa JSON + screenshot"
          >
            ⬇ Relatório
          </button>
          <button
            onClick={onToggleSimXR}
            className={`rounded px-1.5 py-0.5 text-[9px] ${simXR ? 'bg-green-500 text-black' : 'border border-green-500/40 text-green-300 hover:bg-green-500/20'}`}
          >
            {simXR ? 'SIM ON' : 'Simular XR'}
          </button>
          <button onClick={() => setCollapsed(true)} className="px-1 hover:text-white">✕</button>
        </div>
      </div>

      <div className="flex border-b border-green-500/20">
        {(['inputs', 'cena', 'xr', 'macro', 'logs'] as Tab[]).map((t) => (
          <button
            key={t}
            onClick={() => setTab(t)}
            className={`flex-1 px-1 py-1 text-[10px] uppercase ${tab === t ? 'bg-green-500/20 text-green-200' : 'text-green-500/70 hover:text-green-300'}`}
          >
            {t}
          </button>
        ))}
      </div>

      <div className="max-h-[60vh] overflow-y-auto p-2">
        {tab === 'inputs' && (
          <div className="space-y-2">
            <div className="text-green-500/70">fake: {isFakeActive() ? 'ATIVO' : 'inativo'}</div>
            {(['left', 'right'] as const).map((h) => {
              const s = fakeInput[h];
              const grabbing = s.gripValue > 0.7;
              const p = [s.gripWorld.elements[12], s.gripWorld.elements[13], s.gripWorld.elements[14]];
              return (
                <div key={h} className="rounded border border-green-500/20 p-1.5">
                  <div className={`font-bold ${grabbing ? 'text-yellow-300' : 'text-green-300'}`}>
                    {h.toUpperCase()} {grabbing && '✊ GRAB'}
                  </div>
                  <div>grip: {s.gripValue.toFixed(2)}  trg: {s.triggerValue.toFixed(2)}</div>
                  <div>pose: {p.map((v) => v.toFixed(2)).join(', ')}</div>
                </div>
              );
            })}
            <div className="border-t border-green-500/20 pt-2 text-green-500/70">
              <div className="font-bold text-green-400 mb-1">Atalhos teclado</div>
              <div>Q/W = grip L/R · A/S = trigger L/R</div>
              <div>1/2 = ativar mão · setas = mover</div>
              <div>Shift+↑/↓ = Z (frente/trás) · R = reset</div>
            </div>
          </div>
        )}

        {tab === 'cena' && (
          <div className="space-y-1">
            <Row k="meshes" v={String(sceneStats.meshCount)} />
            <Row k="triângulos" v={sceneStats.triCount.toLocaleString()} />
            <Row k="bbox (m)" v={sceneStats.modelBboxSize.map(n => n.toFixed(3)).join(' × ')} />
            <Row k="pos (m)" v={sceneStats.modelGroupPos.map(n => n.toFixed(3)).join(', ')} />
            <Row k="rot (°)" v={sceneStats.modelGroupRotDeg.map(n => n.toFixed(1)).join(', ')} />
            <Row k="escala" v={sceneStats.modelGroupScale.toFixed(3)} />
          </div>
        )}

        {tab === 'xr' && (
          <div className="space-y-1">
            <Row k="modo" v={sceneStats.xrMode ?? '—'} />
            <Row k="FPS" v={String(sceneStats.fps)} />
            <Row k="inputs" v={String(sceneStats.xrInputCount)} />
            <Row k="planos" v={String(sceneStats.xrPlanesCount)} />
            <Row k="hit-test" v={sceneStats.xrHitTestActive ? 'sim' : 'não'} />
            <Row k="navigator.xr" v={typeof navigator !== 'undefined' && 'xr' in navigator ? 'ok' : 'ausente'} />
            <Row k="HTTPS" v={location.protocol === 'https:' ? 'sim' : 'NÃO'} />
          </div>
        )}

        {tab === 'macro' && (
          <div className="space-y-2">
            <div className="text-green-500/70">fase: <span className="text-green-300">{macroState.phase}</span></div>
            <div className="flex gap-1 flex-wrap">
              {macroState.phase !== 'recording' ? (
                <button onClick={startRecording} className="rounded border border-red-500/50 bg-red-500/10 px-2 py-0.5 text-red-300 hover:bg-red-500/20">● Gravar</button>
              ) : (
                <button onClick={stopRecording} className="rounded border border-yellow-500/50 bg-yellow-500/10 px-2 py-0.5 text-yellow-300">■ Parar</button>
              )}
              {macroState.phase !== 'playing' ? (
                <button
                  onClick={() => startPlaying()}
                  disabled={!macroState.current}
                  className="rounded border border-green-500/50 bg-green-500/10 px-2 py-0.5 text-green-300 hover:bg-green-500/20 disabled:opacity-40"
                >▶ Play</button>
              ) : (
                <button onClick={stopPlaying} className="rounded border border-yellow-500/50 bg-yellow-500/10 px-2 py-0.5 text-yellow-300">⏹ Stop</button>
              )}
              <button
                onClick={() => macroState.current && downloadMacro(macroState.current)}
                disabled={!macroState.current}
                className="rounded border border-green-500/40 px-2 py-0.5 hover:bg-green-500/20 disabled:opacity-40"
              >⬇ Salvar</button>
              <button
                onClick={() => fileRef.current?.click()}
                className="rounded border border-green-500/40 px-2 py-0.5 hover:bg-green-500/20"
              >⬆ Carregar</button>
              <input
                ref={fileRef}
                type="file"
                accept="application/json"
                className="hidden"
                onChange={async (e) => {
                  const f = e.target.files?.[0];
                  if (!f) return;
                  try {
                    const macro = await loadMacroFromFile(f);
                    macroState.current = macro;
                    tick((n) => n + 1);
                  } catch { /* noop */ }
                  e.target.value = '';
                }}
              />
            </div>
            {macroState.current && (
              <div className="rounded border border-green-500/20 p-1.5">
                <div className="font-bold text-green-300">{macroState.current.name}</div>
                <div>frames: {macroState.current.frames.length}</div>
                <div>duração: {(macroState.current.duration / 1000).toFixed(1)}s</div>
              </div>
            )}
            {macroState.phase === 'recording' && (
              <div className="text-yellow-300">gravando… {macroState.rec.length} frames</div>
            )}
            <div className="text-green-500/60 leading-tight border-t border-green-500/20 pt-1">
              Use os atalhos do teclado para encenar o bug; depois clique em Parar e Salvar.
              No próximo round, Carregar o JSON e clicar em Play reproduz exatamente.
            </div>
          </div>
        )}

        {tab === 'logs' && (
          <div className="space-y-1">
            <input
              value={logFilter}
              onChange={(e) => setLogFilter(e.target.value)}
              placeholder="filtro… (ex: [XR])"
              className="w-full rounded border border-green-500/30 bg-black/60 px-1 py-0.5 text-green-300"
            />
            <div className="space-y-0.5">
              {logBuffer
                .filter((l) => !logFilter || l.msg.toLowerCase().includes(logFilter.toLowerCase()))
                .slice(-80).reverse()
                .map((l, i) => (
                  <div
                    key={i}
                    className={`break-all leading-tight ${
                      l.level === 'error' ? 'text-red-400' : l.level === 'warn' ? 'text-yellow-300' : 'text-green-300/90'
                    }`}
                  >
                    {l.msg}
                  </div>
                ))}
              {logBuffer.length === 0 && <div className="text-green-500/50 italic">sem logs ainda…</div>}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function Row({ k, v }: { k: string; v: string }) {
  return (
    <div className="flex justify-between gap-2 border-b border-green-500/10 py-0.5">
      <span className="text-green-500/70">{k}</span>
      <span className="text-green-200 break-all text-right">{v}</span>
    </div>
  );
}
