/* ─── EVE Monitor Preview — Radar Dashboard (100% dati reali) ─── */
const { useState, useEffect, useRef, useCallback } = React;

async function apiFetch(url) {
  try {
    const r = await fetch(url, { credentials: 'include' });
    if (!r.ok) return null;
    return await r.json();
  } catch { return null; }
}

const KIND_TAG = {
  hostile:'HOSTILE', cyno:'CYNO', bubble:'BUBBLE', gate_camp:'GATECAMP',
  neutral:'NEUTRAL', all_clear:'CLEAR', kill:'KILL',
  wormhole_signature:'WARN', blob:'GANG', note:'INTEL', hostile_seen:'HOSTILE',
};
const SEV_MAP = { 1:'low', 2:'low', 3:'med', 4:'high', 5:'high' };

function parseEvents(rows) {
  return (rows ?? []).map(r => ({
    id:    r.id,
    ts:    r.observed_at ? new Date(r.observed_at).getTime() : Date.now(),
    tag:   KIND_TAG[r.kind] ?? 'INTEL',
    sev:   SEV_MAP[r.severity] ?? 'med',
    sys:   r.system_name || String(r.system_id || '—'),
    pilot:  r.hostile_tags?.[0] || (r.reporters || []).find(x => !x.includes(':') && x.length > 2) || null,
    charId: undefined,
    text:  r.message || r.description || r.raw_text || r.kind || '—',
  }));
}

/* ── useAutoLocation: sistema corrente del PG via ESI ── */
function useAutoLocation() {
  const [loc, setLoc] = useState(null);
  useEffect(() => {
    let alive = true;
    async function load() {
      const d = await apiFetch('/api/radar-00/auto-location');
      if (!alive) return;
      if (d?.ok && d.system_name) setLoc(d.system_name);
    }
    load();
    const id = setInterval(load, 30_000); // aggiorna ogni 30s
    return () => { alive = false; clearInterval(id); };
  }, []);
  return loc;
}

/* ── useCharacter: nome PG ── */
function useCharacter() {
  const [info, setInfo] = useState({ pilot: '—', region: '—' });
  useEffect(() => {
    apiFetch('/api/radar-00/character').then(d => {
      if (d?.ok) setInfo({
        pilot:  d.character_name || d.name || '—',
        region: d.region_name || '—',
      });
    });
  }, []);
  return info;
}

/* ── BFS filter: sigma-coords reali, clamped a radar radius ── */
function filterByRadius(allSystems, allEdges, focusName, hops) {
  const adj = new Map();
  for (const s of allSystems) adj.set(s.id, new Set());
  for (const [a, b] of allEdges) {
    adj.get(a)?.add(b);
    adj.get(b)?.add(a);
  }
  const inView = new Set([focusName]);
  let frontier = [focusName];
  for (let h = 0; h < hops; h++) {
    const next = [];
    for (const n of frontier)
      for (const nb of adj.get(n) ?? [])
        if (!inView.has(nb)) { inView.add(nb); next.push(nb); }
    frontier = next;
    if (!frontier.length) break;
  }
  if (inView.size < 3) for (const s of allSystems) inView.add(s.id);
  const sub = allSystems.filter(s => inView.has(s.id));
  const subEdges = allEdges.filter(([a, b]) => inView.has(a) && inView.has(b));

  // Posizione focus
  const focusSys = allSystems.find(s => s.id === focusName);
  const fx = focusSys?.x ?? 0.5, fy = focusSys?.y ?? 0.5;

  // Bbox solo da sistemi con coordinate sigma valide (has_coord !== false)
  const validSub = sub.filter(s => s.has_coord !== false);
  const bboxSrc = validSub.length >= 2 ? validSub : sub;
  let xMin=Infinity, xMax=-Infinity, yMin=Infinity, yMax=-Infinity;
  for (const s of bboxSrc) {
    if (s.x < xMin) xMin = s.x; if (s.x > xMax) xMax = s.x;
    if (s.y < yMin) yMin = s.y; if (s.y > yMax) yMax = s.y;
  }
  const span = Math.max(xMax - xMin, yMax - yMin, 0.06);
  // scale: mappa span → 1.3 (rimane dentro radar con margine)
  const scale = 1.3 / span;
  const clamp = v => Math.max(-0.82, Math.min(0.82, v));

  // Prima passata: sistemi con coord valide
  const posMap = new Map();
  for (const s of sub) {
    if (s.has_coord === false) continue;
    posMap.set(s.id, {
      x: clamp((s.x - fx) * scale),
      y: clamp((s.y - fy) * scale),
    });
  }

  // Seconda passata: sistemi senza coord → media dei vicini con coord
  for (const s of sub) {
    if (posMap.has(s.id)) continue;
    const nbs = [...(adj.get(s.id) ?? [])].map(id => posMap.get(id)).filter(Boolean);
    if (nbs.length > 0) {
      posMap.set(s.id, {
        x: +(nbs.reduce((a, n) => a + n.x, 0) / nbs.length).toFixed(3),
        y: +(nbs.reduce((a, n) => a + n.y, 0) / nbs.length).toFixed(3),
      });
    } else {
      posMap.set(s.id, { x: 0, y: 0 });
    }
  }

  return {
    systems: sub.map(s => {
      const p = posMap.get(s.id) ?? { x: 0, y: 0 };
      return { ...s, x: +p.x.toFixed(3), y: +p.y.toFixed(3) };
    }),
    edges: subEdges,
  };
}

/* ═══════════════════════ RADAR PAGE ═══════════════════════ */
function RadarPage({ shared }) {
  const { focus, setFocus, alerts, setAlerts, volume, setVolume, muteAll, setMuteAll } = shared;

  const rd = window.RadarData;
  // Tutti i sistemi del territorio (non filtrati, con coordinate raw)
  const allSystems = rd.allSystems ?? rd.systems;
  const allEdges   = rd.allEdges   ?? rd.edges;

  const [radius, setRadius] = useState(2);
  const { systems, edges } = filterByRadius(allSystems, allEdges, focus, radius);

  /* sweep */
  const [sweepAngle, setSweepAngle] = useState(0);
  useEffect(() => {
    let raf, last = performance.now();
    const tick = now => {
      const dt = (now - last) / 1000; last = now;
      setSweepAngle(a => (a + dt * 60) % 360);
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);

  /* intel feed: polling ogni 8s */
  const [events, setEvents]         = useState([]);
  const [paused, setPaused]         = useState(false);
  const [hotEvent, setHotEvent]     = useState(null);
  const [eventCount, setEventCount] = useState(0);
  const lastTsRef = useRef(0);

  const fetchEvents = useCallback(async () => {
    const data = await apiFetch('/api/radar-00/events?limit=60');
    if (!data?.ok) return;
    const parsed = parseEvents(data.rows ?? []);
    setEvents(parsed);
    setEventCount(data.total ?? parsed.length);

    if (!paused && parsed.length > 0) {
      const newOnes = parsed.filter(e => e.ts > lastTsRef.current);
      for (const e of newOnes.slice(0, 2)) {
        setHotEvent(e.sys);
        setTimeout(() => setHotEvent(null), 1300);
        const tagKey = { HOSTILE:'hostile', CYNO:'cyno', BUBBLE:'bubble',
                         GATECAMP:'gatecamp', NEUTRAL:'neutral', CLEAR:'clear' }[e.tag];
        if (tagKey && alerts[tagKey] && !muteAll) {
          const meta = window.ALERT_SOUNDS_REF?.[tagKey];
          if (meta && window.__playBlip) window.__playBlip(meta.freq, 0.1, meta.type, 0.12, meta.sev);
        }
      }
      lastTsRef.current = parsed[0].ts;
    }
  }, [paused, alerts, muteAll]);

  useEffect(() => {
    fetchEvents();
    const id = setInterval(fetchEvents, 8000);
    return () => clearInterval(id);
  }, [fetchEvents]);

  /* risk dal sistema focus */
  const focusedSystem = systems.find(s => s.id === focus) || systems[0];
  const risk = focusedSystem?.risk ?? 0;

  /* stats */
  const [parseRate, setParseRate] = useState(null);
  useEffect(() => {
    apiFetch('/api/radar-00/stats').then(d => {
      if (d?.ok) {
        const rate = d.events_per_min ?? d.parse_rate ?? null;
        setParseRate(typeof rate === 'number' ? rate : null);
      }
    });
  }, []);

  return (
    <div style={{
      display: 'grid', gridTemplateColumns: '1fr 268px', gridTemplateRows: '1fr',
      gap: 5, padding: 5, height: 'calc(100vh - 30px)',
      boxSizing: 'border-box', overflow: 'hidden',
    }}>
      {/* sinistra */}
      <div style={{ display: 'grid', gridTemplateRows: '1fr 168px', gap: 5, minHeight: 0 }}>

        <Panel style={{ padding: 0, display: 'flex', flexDirection: 'column', minHeight: 0 }}>
          <PanelHeader>
            <span>▸ CONSTELLATION</span>
            <span style={{ color: '#5b6577', marginLeft: 8, letterSpacing: '0.18em' }}>
              {systems.length}sys · {edges.length}j
            </span>
            <span style={{ flex: 1 }}/>
            {/* Controllo raggio */}
            <span style={{ display:'flex', alignItems:'center', gap:4, marginRight:6 }}>
              <Mono style={{ fontSize:8, color:'#5b6577', letterSpacing:'0.2em' }}>RANGE</Mono>
              {[2,3,5,7,10].map(r => (
                <button key={r} onClick={() => setRadius(r)} style={{
                  background: radius===r ? 'rgba(56,189,248,0.18)' : 'transparent',
                  border: `1px solid ${radius===r ? '#38bdf8' : 'rgba(56,189,248,0.25)'}`,
                  color: radius===r ? '#38bdf8' : '#5b6577',
                  fontFamily:"'JetBrains Mono',monospace", fontSize:8,
                  padding:'1px 5px', borderRadius:1, cursor:'pointer',
                  letterSpacing:'0.1em',
                }}>{r}J</button>
              ))}
            </span>
            <Pill color="cyan">F · {focus}</Pill>
            <Pill color={events.length > 0 ? 'green' : 'dim'}>LIVE</Pill>
          </PanelHeader>
          <div style={{ flex: 1, position: 'relative', minHeight: 0 }}>
            <ConstellationMap systems={systems} edges={edges} focus={focus}
              onFocus={setFocus} sweepAngle={sweepAngle} hotEvent={hotEvent}/>
          </div>
        </Panel>

        <div style={{ display: 'grid', gridTemplateColumns: '0.9fr 0.85fr 1.05fr 1.15fr', gap: 5, minHeight: 0 }}>
          <Panel style={{ padding: 0, display: 'flex', flexDirection: 'column' }}>
            <PanelHeader>▸ JUMPS · 1</PanelHeader>
            <div style={{ padding: '5px 6px', flex: 1, overflow: 'hidden' }}>
              <AdjacentSystems systems={systems} focus={focus} onFocus={setFocus}/>
            </div>
          </Panel>
          <Panel style={{ padding: 0, display: 'flex', flexDirection: 'column' }}>
            <PanelHeader>▸ SENSOR</PanelHeader>
            <div style={{ padding: '4px 8px', flex: 1, overflow: 'hidden' }}>
              <SensorStatus
                rate={typeof parseRate === 'number' ? parseRate : '—'}
                eventCount={eventCount}
                folder="bridge locale"/>
            </div>
          </Panel>
          <Panel style={{ padding: 0, display: 'flex', flexDirection: 'column' }}>
            <PanelHeader>▸ AUDIO · ALERTS</PanelHeader>
            <div style={{ padding: '2px 8px 4px', flex: 1, overflow: 'hidden', display: 'flex' }}>
              <SoundAlerts alerts={alerts} setAlerts={setAlerts}
                volume={volume} setVolume={setVolume}
                muteAll={muteAll} setMuteAll={setMuteAll}/>
            </div>
          </Panel>
          <Panel style={{ padding: 0, display: 'flex', flexDirection: 'column' }}>
            <PanelHeader>
              ▸ KILLBOARD · zKill
              <span style={{ flex: 1 }}/>
              <a href="https://zkillboard.com/" target="_blank" rel="noopener noreferrer"
                style={{ color: '#38bdf8', fontFamily: "'JetBrains Mono',monospace",
                         fontSize: 7.5, letterSpacing: '0.2em', textDecoration: 'none' }}>
                OPEN ↗
              </a>
            </PanelHeader>
            <div style={{ padding: '2px 8px', flex: 1, overflow: 'auto' }}>
              <KillboardLive/>
            </div>
          </Panel>
        </div>
      </div>

      {/* destra: gauge + feed */}
      <Panel style={{ display: 'flex', flexDirection: 'column', padding: 0, minHeight: 0 }}>
        <PanelHeader>
          ▸ {focus}
          <span style={{ color: '#5b6577', marginLeft: 6, letterSpacing: '0.18em' }}>
            · {focusedSystem?.hub ? 'HOME' : 'WATCHED'}
            {focusedSystem?.region_name ? ' · ' + focusedSystem.region_name : ''}
          </span>
        </PanelHeader>
        <div style={{ padding: '6px 8px 4px' }}>
          <RiskGauge value={Math.round(risk)} delta={0}/>
        </div>
        <div style={{
          borderTop: '1px solid rgba(56,189,248,0.15)',
          padding: '5px 8px 6px',
          flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0,
        }}>
          <IntelFeed events={events} paused={paused} onTogglePause={() => setPaused(p => !p)}/>
        </div>
      </Panel>
    </div>
  );
}

/* ── Killboard: eventi kind=kill reali, nessun mock ── */
function KillboardLive() {
  const [kills, setKills] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let alive = true;
    async function load() {
      const d = await apiFetch('/api/radar-00/events?kind=kill&limit=10');
      if (!alive) return;
      setLoading(false);
      if (!d?.ok || !d.rows?.length) { setKills([]); return; }
      // Filtra kind=kill; i campi reali disponibili sono hostile_tags, reporters, system_name, message
      const killRows = d.rows.filter(r => r.kind === 'kill');
      setKills(killRows.slice(0, 10).map(r => {
        const hostile = r.hostile_tags?.[0] || null;
        const reporter = r.reporters?.[0] || null;
        const pilot = hostile || reporter || '—';
        // Prova a estrarre ship dal messaggio (es. "ZENERBREAKDOWN Sabre")
        const shipMatch = r.message ? r.message.match(/\b(Sabre|Loki|Vargur|Rorqual|Cerberus|Ishtar|Tengu|Legion|Proteus|Machariel|Nidhoggur|Hel|Naglfar|Revelation|Phoenix|Moros|Thanatos|Chimera|Wyvern|Aeon|Nyx|Avatar|Erebus|Ragnarok)\b/i) : null;
        const ship = shipMatch ? shipMatch[0] : r.system_name || '—';
        return {
          killId: undefined,
          charId: undefined,
          time:   r.observed_at ? new Date(r.observed_at).toTimeString().slice(0,5) : '—',
          ship,
          pilot,
          value:  '—',
          loss:   false,
          sys:    r.system_name || '—',
        };
      }));
    }
    load();
    const id = setInterval(load, 30_000);
    return () => { alive = false; clearInterval(id); };
  }, []);

  if (loading) return (
    <div style={{ color: '#5b6577', fontSize: 9, letterSpacing: '0.2em', padding: '8px 0' }}>
      LOADING...
    </div>
  );
  if (!kills.length) return (
    <div style={{ color: '#5b6577', fontSize: 9, letterSpacing: '0.15em', padding: '8px 0' }}>
      Nessun kill registrato nel radar.<br/>
      <a href="https://zkillboard.com/" target="_blank" rel="noopener noreferrer"
        style={{ color: '#38bdf8', textDecoration: 'none' }}>
        → zkillboard.com ↗
      </a>
    </div>
  );
  return <Killboard kills={kills}/>;
}

/* ═══════════════════════ APP ROUTER ═══════════════════════ */
function App() {
  const [page, setPage] = useState('RADAR');

  // Focus: prima prova auto-location (sistema corrente del PG)
  // poi fallback al primo sistema hub dei dati live
  const autoLoc = useAutoLocation();
  const defaultFocus =
    (window.RadarData.systems.find(s => s.hub) || window.RadarData.systems[0])?.id || 'YA0-XJ';
  const [focus, setFocus] = useState(defaultFocus);

  // Quando arriva l'auto-location, aggiorna il focus
  useEffect(() => {
    if (autoLoc) setFocus(autoLoc);
  }, [autoLoc]);

  const [alerts, setAlerts] = useState({
    hostile: true, cyno: true, bubble: true,
    gatecamp: true, neutral: false, clear: false,
  });
  const [volume, setVolume]   = useState(70);
  const [muteAll, setMuteAll] = useState(false);

  const char = useCharacter();
  const focusSys = window.RadarData.systems.find(s => s.id === focus);

  useEffect(() => { window.__masterVol = (muteAll ? 0 : volume) / 100; }, [volume, muteAll]);
  useEffect(() => {
    window.__playBlip = window.playBlip;
    window.ALERT_SOUNDS_REF = window.ALERT_SOUNDS;
  }, []);

  const shared = { focus, setFocus, alerts, setAlerts, volume, setVolume, muteAll, setMuteAll };

  return (
    <div style={{
      minHeight: '100vh',
      background: 'radial-gradient(ellipse at 50% 0%, rgba(56,189,248,0.04) 0%, transparent 60%), #0a0e14',
      color: '#e8ecf2', fontFamily: "'Space Grotesk', sans-serif",
    }}>
      <TopBar
        pilot={char.pilot}
        region={focusSys?.region_name || char.region || '—'}
        system={focus}
        online={true}
        page={page}
        onNav={setPage}
      />
      {page === 'RADAR'    && <RadarPage shared={shared}/>}
      {page === 'INTEL'    && <IntelPage/>}
      {page === 'MARKET'   && <MarketPage/>}
      {page === 'KILLS'    && <KillsPage/>}
      {page === 'SETTINGS' && <SettingsPage/>}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
