import { useEffect, useRef, useState } from "react";
import "./App.css";
import PlayerCard from "./components/playercard";
import Radar from "./components/radar";
import { getLatency, Latency } from "./components/latency";
import Scoreboard from "./components/scoreboard";
import KillFeed from "./components/killfeed";
import ShareModal from "./components/ShareModal";
import PipWindow from "./components/PipWindow";
import ChooseSelfModal from "./components/ChooseSelfModal";
import { THEMES, loadTheme, applyTheme, getThemes } from "./themes/index.js";

const CONNECTION_TIMEOUT = 5000;

// WebSocket connects to the same host and port as the HTTP server.
// - Local (http): ws://localhost:8082/ws
// - Via Cloudflare Tunnel (https): wss://your-tunnel.trycloudflare.com/ws  (no port — tunnel handles it)
// window.location.host includes the port when non-standard (e.g. "localhost:8082")
// but omits it for standard ports (443 for https, 80 for http) — exactly what we need.
const wsURL = (window.location.protocol === "https:" ? "wss://" : "ws://")
  + window.location.host + "/ws";

const DEFAULT_SETTINGS = {
  dotSize: 1,
  bombSize: 0.5,
  coneLength: 1,
  showAllNames: false,
  showEnemyNames: true,
  showViewCones: false,
  showGrenades: true,
  showSmoke: true,
  showFire: true,
  showGrenadeLabels: true,
  showGrenadeTrajectory: true,
  showDroppedWeapons: true,
  showHealthBars: true,
  showAmmo: true,
  showArmor: true,
  showPing: true,
  showMoney: true,
  showFlashEffect: true,
  showDotStates: true,
  showBombTimer: true,
  showKillFeed: true,
  showTCards: true,
  showCTCards: true,
  showBombOnMap: true,
  autoZoom: false,
  showAdvisories: true,
  advisoriesOpacity: 1.0,
  followYourself: false,
  /** m_idx of the self player (default "0" = unselected). Used by
   *  followYourself + followYourselfRotation and to visually highlight
   *  the local player's dot on the radar.                        */
  whichPlayerAreYou: "0",
  /** Steam ID of the self player (stable across deaths/respawns).
   *  Used together with whichPlayerAreYou for reliable self identification. */
  yourSteamId: "",
  followYourselfRotation: false,
  followZoom: 3.5,
  showPip: false,
  showIndicators: true,
  indicatorSize: 1,
  flagDisplayMode: "abbreviated",
  indicatorColors: {
    ducking: "#4a9eff",
    shifting: "#fbbf24",
    scoped: "#10b981",
    reload: "#ef4444",
  },

  // ── Group 1: Map image adjustments ──────────────────────────────
  mapBrightness: 1.0,   // filter brightness()
  mapContrast: 1.0,     // filter contrast()
  mapOpacity: 1.0,      // image opacity
  mapBlur: 0,           // filter blur(px)

  // ── Group 1: Display element opacities ──────────────────────────
  nameOpacity: 1.0,        // player name labels
  indicatorOpacity: 1.0,   // flag indicators (S/W/Z/R)
  weaponIconOpacity: 1.0,  // weapon icons above dots

  // ── Group 2: Theme / colors ─────────────────────────────────────
  enemyColor: "#FF4444",   // enemy dot color
  backgroundDim: 0,        // page background dim 0..0.9
  dotOpacity: 1.0,         // player dot opacity
  dotGlow: 0,              // player dot glow strength 0..1

  // ── Group 3: View cone ──────────────────────────────────────────
  coneWidth: 1.0,          // cone width multiplier
  coneOpacity: 1.0,        // cone opacity multiplier
  scopedConeNarrow: true,  // narrow + extend cone while scoped

  // ── Group 4: Sound alerts ───────────────────────────────────────
  soundAlerts: false,      // play sound on bomb plant / sole survivor
  soundVolume: 0.5,        // 0..1

  // ── Group 5: Dropped weapon ESP ──────────────────────────────────
  droppedWeaponSize: 1.0,   // icon size multiplier
  droppedWeaponColor: "#94a3b8",  // fallback diamond color
  droppedWeaponOpacity: 0.92,     // icon opacity
  droppedWeaponFilterMode: "all",  // "all" | "custom"
  droppedWeaponFilterList: [],     // ["ak47", "awp", ...] when mode=custom
  showDroppedUtilities: true,      // separate toggle for nades/decoy/molotov
  droppedUtilitySize: 1.0,        // utility icon size multiplier (independent)
  droppedUtilityOpacity: 0.92,    // utility icon opacity
  droppedUtilityColor: "#94a3b8", // utility fallback diamond color
  _settingsVersion: 0,       // incremented on breaking changes — one-time migrations
};

const SETTINGS_VERSION = 2; // bump when adding a new migration below

const loadSettings = () => {
  try {
    const saved = localStorage.getItem("radarSettings");
    const settings = saved ? { ...DEFAULT_SETTINGS, ...JSON.parse(saved) } : { ...DEFAULT_SETTINGS };
    // Migration v1: yourSteamId was added. Old settings have whichPlayerAreYou set but
    // no yourSteamId, making the stored m_idx stale across sessions.
    if (settings._settingsVersion < 1) {
      if (settings.whichPlayerAreYou !== "0" && !settings.yourSteamId) {
        settings.whichPlayerAreYou = "0";
      }
      settings._settingsVersion = 1;
    }
    // Migration v2: dropped weapon filter + utilities toggle. Defaults handle the
    // spread, no explicit migration needed.
    if (settings._settingsVersion < 2) {
      settings._settingsVersion = 2;
    }
    return settings;
  } catch { return { ...DEFAULT_SETTINGS }; }
};

// ── RadarColumn — MUST be defined outside App so React doesn't remount it ─────
const RadarColumn = ({
  roundInfo, localTeam, playerArray, mapData, averageLatency,
  bombData, grenadeArray, droppedWeaponArray, settings, setSettings,
  lockedPlayerIdx, setLockedPlayerIdx,
}) => {
  if (!mapData) return (
    <div className="flex flex-col items-center gap-2 flex-1" style={{ height: "100%", width: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}>
      <span style={{ fontSize: 11, color: "var(--text-muted)" }}>Loading map data…</span>
    </div>
  );
  return (
    <div className="flex flex-col items-center gap-2 flex-1" style={{ height: "100%", width: "100%", position: "relative" }}>
    <Radar
      playerArray={playerArray}
      radarImage={`./data/${mapData.name}/radar.png`}
      mapData={mapData}
      localTeam={localTeam}
      averageLatency={averageLatency}
      bombData={bombData}
      grenadeArray={grenadeArray}
      droppedWeaponArray={droppedWeaponArray}
      roundInfo={roundInfo}
      settings={settings}
      setSettings={setSettings}
      lockedPlayerIdx={lockedPlayerIdx}
      setLockedPlayerIdx={setLockedPlayerIdx}
    />
    {/* Kill feed — overlay on radar, bottom-right, only in non-fullscreen */}
    {settings?.showKillFeed !== false && (
      <div style={{
        position: "absolute",
        bottom: 12,
        right: 12,
        zIndex: 50,
        pointerEvents: "none",
      }}>
        <KillFeed playerArray={playerArray} />
      </div>
    )}
  </div>
  );
};

const App = () => {
  const [averageLatency, setAverageLatency] = useState(0);
  const [playerArray, setPlayerArray]       = useState([]);
  const [mapData, setMapData]               = useState();
  const [localTeam, setLocalTeam]           = useState();
  const [bombData, setBombData]             = useState();
  const [grenadeArray, setGrenadeArray]     = useState([]);
  const [droppedWeaponArray, setDroppedWeaponArray] = useState([]);
  const [roundInfo, setRoundInfo]           = useState(null);
  const [settings, setSettings]             = useState(loadSettings());
  const [showShareModal, setShowShareModal] = useState(false);
  const [showChooseSelfModal, setShowChooseSelfModal] = useState(false);
  const [pipOpen, setPipOpen]               = useState(false);
  const [lockedPlayerIdx, setLockedPlayerIdx] = useState(null);
  const [showTeamList, setShowTeamList]     = useState("both");
  const [isMobile, setIsMobile]             = useState(false);
  const [tScore, setTScore]                 = useState(0);
  const [ctScore, setCtScore]               = useState(0);

  /* Theme state */
  const [currentTheme, setCurrentTheme] = useState(loadTheme);
  const [showThemeSelector, setShowThemeSelector] = useState(false);

  /* Theme handler */
  const handleThemeChange = (themeId) => {
    setCurrentTheme(themeId);
    applyTheme(themeId);
    setShowThemeSelector(false);
  };
  const currentThemeData = THEMES[currentTheme] || THEMES.default;
  const availableThemes = getThemes();

  const prevRoundRef    = useRef(null);
  const prevAliveTRef   = useRef(null);
  const prevAliveCTRef  = useRef(null);
  const roundEndedRef   = useRef(false);

  /* Detect mobile */
  useEffect(() => {
    const checkMobile = () => setIsMobile(window.innerWidth < 1024);
    checkMobile();
    window.addEventListener("resize", checkMobile);
    return () => window.removeEventListener("resize", checkMobile);
  }, []);

  /* Close theme selector on click outside */
  useEffect(() => {
    if (!showThemeSelector) return;
    const handleClickOutside = (e) => {
      if (!e.target.closest('button')) {
        setShowThemeSelector(false);
      }
    };
    document.addEventListener("click", handleClickOutside);
    return () => document.removeEventListener("click", handleClickOutside);
  }, [showThemeSelector]);

  /* Save settings */
  useEffect(() => {
    localStorage.setItem("radarSettings", JSON.stringify(settings));
  }, [settings]);

  /* Auto-unlock POV lock when map changes */
  useEffect(() => {
    setLockedPlayerIdx(null);
  }, [mapData?.name]);

  /* Show choose-self modal when player hasn't selected themselves yet */
  useEffect(() => {
    if (settings.whichPlayerAreYou === "0" && playerArray.length > 0 && localTeam != null) {
      setShowChooseSelfModal(true);
    } else {
      setShowChooseSelfModal(false);
    }
  }, [settings.whichPlayerAreYou, playerArray, localTeam]);

  /* ── Handle choose self ─────────────────────────────────────────────── */
  const handleChooseSelf = ({ m_idx, steam_id }) => {
    setSettings(prev => ({
      ...prev,
      whichPlayerAreYou: String(m_idx),
      // Only store steam_id if valid (non-empty and not "0") — "0" means unknown.
      yourSteamId: (steam_id && steam_id !== "0") ? String(steam_id) : "",
      followYourself: true,
    }));
    setShowChooseSelfModal(false);
  };

  const handleSkipChooseSelf = () => {
    setShowChooseSelfModal(false);
  };

  /* ── WebSocket with exponential-backoff reconnect ────────────────────────── */
  useEffect(() => {
    let ws          = null;
    let attempt     = 0;
    let retryTimer  = null;
    let destroyed   = false;
    let loadedMap   = "";   // guard: only fetch data.json when map actually changes

    const setStatus = (text) => {
      const el = document.getElementsByClassName("radar_message")[0];
      if (el) el.textContent = text;
    };

    const connect = () => {
      if (destroyed) return;
      try {
        ws = new WebSocket(wsURL);
      } catch (err) {
        setStatus(`WebSocket error: ${err}`);
        scheduleReconnect();
        return;
      }

      const connTimeout = setTimeout(() => {
        if (ws.readyState !== WebSocket.OPEN) ws.close();
      }, CONNECTION_TIMEOUT);

      ws.onopen = () => {
        clearTimeout(connTimeout);
        attempt = 0;
        window.__radarWs = ws;   // expose for settings panel config commands
        setStatus("");
      };

      ws.onclose = () => {
        clearTimeout(connTimeout);
        if (!destroyed) scheduleReconnect();
      };

      ws.onerror = (err) => {
        clearTimeout(connTimeout);
        // onclose fires right after onerror; reconnect scheduled there
      };

      ws.onmessage = async (event) => {
        setAverageLatency(getLatency());
        const parsedData = JSON.parse(typeof event.data === "string" ? event.data : await event.data.text());
        setPlayerArray(parsedData.m_players ?? []);
        setLocalTeam(parsedData.m_local_team ?? 0);
        setBombData(parsedData.m_bomb ?? null);
        setGrenadeArray(parsedData.m_grenades ?? []);
        setDroppedWeaponArray(parsedData.m_dropped_weapons ?? []);
        setRoundInfo(parsedData.m_round_info ?? null);

        const map = parsedData.m_map;
        // Validate map name before fetching
        if (map && map !== "invalid" && map !== "" && map !== loadedMap) {
          loadedMap = map;   // prevent fetching data.json on every frame
          fetch(`data/${map}/data.json`)
            .then(res => {
              if (!res.ok) {
                throw new Error(`Map data not found: ${res.status}`);
              }
              return res.json();
            })
            .then(json => {
              // Validate that mapData has required properties
              if (json.x === undefined || json.y === undefined || json.scale === undefined) {
                loadedMap = "";   // reset so we retry on next message
                return;
              }
              setMapData({ ...json, name: map });
              document.body.style.backgroundImage = `url(./data/${map}/background.png)`;
            })
            .catch(err => {
              loadedMap = "";   // reset so we retry on next message
            });
        }
      };
    };

    const scheduleReconnect = () => {
      if (destroyed) return;
      // Exponential backoff: 500ms, 1s, 2s, 4s, 8s, 16s (max)
      const delay = Math.min(500 * Math.pow(2, attempt), 16000)
                  + Math.random() * 200; // jitter
      attempt++;
      setStatus(`Reconnecting in ${(delay / 1000).toFixed(1)}s… (attempt ${attempt})`);
      retryTimer = setTimeout(connect, delay);
    };

    connect();

    return () => {
      destroyed = true;
      clearTimeout(retryTimer);
      if (ws) ws.close();
    };
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
  /* ── END WebSocket ────────────────────────────────────────────────────────── */

  /* ── Sound alerts: bomb plant + defuse (Web Audio beep) ───────────── */
  const prevBombPlantedRef = useRef(false);
  const prevDefusedRef = useRef(false);
  const defuseBeepIntervalRef = useRef(null);
  const audioCtxRef = useRef(null);

  const playBeep = (freq = 880, durationMs = 180) => {
    if (!settings?.soundAlerts) return;
    try {
      if (!audioCtxRef.current) {
        audioCtxRef.current = new (window.AudioContext || window.webkitAudioContext)();
      }
      const ctx = audioCtxRef.current;
      const osc = ctx.createOscillator();
      const gain = ctx.createGain();
      osc.type = "sine";
      osc.frequency.value = freq;
      gain.gain.value = (settings?.soundVolume ?? 0.5) * 0.3;
      osc.connect(gain);
      gain.connect(ctx.destination);
      osc.start();
      osc.stop(ctx.currentTime + durationMs / 1000);
    } catch { /* audio not available */ }
  };

  useEffect(() => {
    if (!settings?.soundAlerts) return;

    // Bomb plant — rising two-tone beep
    const planted = !!(bombData?.m_blow_time > 0 || roundInfo?.m_bomb_planted);
    if (planted && !prevBombPlantedRef.current) {
      playBeep(660, 150);
      setTimeout(() => playBeep(990, 200), 160);
    }
    prevBombPlantedRef.current = planted;

    // Defusing beep loop: two beeps per second (bip bip — pause — bip bip)
    const defusing = !! (bombData?.m_is_defusing || bombData?.state === "defusing");
    if (defusing && !defuseBeepIntervalRef.current) {
      defuseBeepIntervalRef.current = setInterval(() => {
        // first beep
        playBeep(1000, 150);
        // second beep after 150ms
        setTimeout(() => playBeep(1000, 150), 150);
      }, 1000);
    } else if (!defusing && defuseBeepIntervalRef.current) {
      clearInterval(defuseBeepIntervalRef.current);
      defuseBeepIntervalRef.current = null;
    }

    // Bomb defused — two short beeps (high then low) on transition to defused
    const defused = !!(bombData?.m_is_defused || roundInfo?.m_bomb_defused);
    if (defused && !prevDefusedRef.current) {
      // Ensure any defusing interval is stopped
      if (defuseBeepIntervalRef.current) {
        clearInterval(defuseBeepIntervalRef.current);
        defuseBeepIntervalRef.current = null;
      }
      playBeep(1050, 100);
      setTimeout(() => playBeep(800, 100), 120);
    }
    prevDefusedRef.current = defused;
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [bombData, roundInfo, playerArray, settings?.soundAlerts]);
  /* ── END Sound alerts ─────────────────────────────────────────────────────── */

  /* ── Round-end detection: client-side score tracking ─────────────────────── */
  useEffect(() => {
    if (!roundInfo || playerArray.length === 0) return;

    const currentRound = roundInfo.m_round_number ?? 0;
    const tAlive  = playerArray.filter(p => p.m_team === 2 && !p.m_is_dead).length;
    const ctAlive = playerArray.filter(p => p.m_team === 3 && !p.m_is_dead).length;
    const bombExploded = roundInfo.m_bomb_exploded ?? false;
    const bombDefused  = roundInfo.m_bomb_defused  ?? false;

    // Reset round-end flag when round number changes
    if (prevRoundRef.current !== null && currentRound !== prevRoundRef.current) {
      roundEndedRef.current = false;
    }

    if (!roundEndedRef.current) {
      // T win: all CT killed
      if (prevAliveCTRef.current !== null && prevAliveCTRef.current > 0 && ctAlive === 0) {
        setTScore(s => s + 1);
        roundEndedRef.current = true;
      }
      // CT win: all T killed
      else if (prevAliveTRef.current !== null && prevAliveTRef.current > 0 && tAlive === 0) {
        setCtScore(s => s + 1);
        roundEndedRef.current = true;
      }
      // T win: bomb exploded
      else if (bombExploded) {
        setTScore(s => s + 1);
        roundEndedRef.current = true;
      }
      // CT win: bomb defused
      else if (bombDefused) {
        setCtScore(s => s + 1);
        roundEndedRef.current = true;
      }
    }

    prevRoundRef.current   = currentRound;
    prevAliveTRef.current  = tAlive;
    prevAliveCTRef.current = ctAlive;
  }, [playerArray, roundInfo]);
  /* ── END Round-end detection ──────────────────────────────────────────────── */

  const terrorists        = playerArray.filter(p => p.m_team === 2);
  const counterTerrorists = playerArray.filter(p => p.m_team === 3);

  const showTCards  = settings.showTCards  !== false;
  const showCTCards = settings.showCTCards !== false;

  return (
    <>
    <div
      className="fixed inset-0 flex flex-col overflow-hidden"
      style={{ background: "var(--bg-base)" }}
    >
      {/* Background dim overlay (Group 2) */}
      {(settings?.backgroundDim ?? 0) > 0 && (
        <div style={{
          position: "fixed", inset: 0,
          background: "#000",
          opacity: Math.min(settings.backgroundDim, 0.9),
          pointerEvents: "none",
          zIndex: 1,
        }} />
      )}
      {/* ── Top bar ─────────────────────────────────────────────────────────── */}
      <div style={{
        display: "flex",
        alignItems: "center",
        justifyContent: "flex-end",
        gap: 8,
        padding: "8px 16px",
        borderBottom: "1px solid var(--bg-border-dim)",
        background: "var(--bg-panel)",
        flexShrink: 0,
        zIndex: 100,
      }}>
        {/* Share Radar — opens Cloudflare Tunnel modal */}
        <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
          <button
            onClick={() => setShowShareModal(true)}
            title="Share with friends outside your network using Cloudflare Tunnel"
            style={{
              display: "flex", alignItems: "center", gap: 6,
              padding: "6px 12px", borderRadius: 6,
              background: "transparent",
              border: "1px solid var(--bg-border-dim)",
              color: "var(--text-secondary)",
              fontSize: 12, fontWeight: 700, cursor: "pointer",
              fontFamily: "inherit", letterSpacing: "0.04em", transition: "all 0.15s",
            }}
            onMouseEnter={e => { e.currentTarget.style.borderColor = "var(--bg-border)"; e.currentTarget.style.color = "var(--text-primary)"; }}
            onMouseLeave={e => { e.currentTarget.style.borderColor = "var(--bg-border-dim)"; e.currentTarget.style.color = "var(--text-secondary)"; }}
          >
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
              <rect x="9" y="9" width="13" height="13" rx="2" /><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
            </svg>
            Share Radar
          </button>

          {/* PiP toggle button */}
          <button
            onClick={() => setPipOpen(prev => !prev)}
            title="Picture-in-Picture floating radar"
            style={{
              display: "flex", alignItems: "center", gap: 6,
              padding: "6px 12px", borderRadius: 6,
              background: pipOpen ? "rgba(74,158,255,0.12)" : "transparent",
              border: `1px solid ${pipOpen ? "rgba(74,158,255,0.5)" : "var(--bg-border-dim)"}`,
              color: pipOpen ? "var(--ct-color)" : "var(--text-secondary)",
              fontSize: 12, fontWeight: 700, cursor: "pointer",
              fontFamily: "inherit", letterSpacing: "0.04em", transition: "all 0.15s",
            }}
            onMouseEnter={e => { if (!pipOpen) { e.currentTarget.style.borderColor = "var(--bg-border)"; e.currentTarget.style.color = "var(--text-primary)"; }}}
            onMouseLeave={e => { if (!pipOpen) { e.currentTarget.style.borderColor = "var(--bg-border-dim)"; e.currentTarget.style.color = "var(--text-secondary)"; }}}
          >
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
              <rect x="2" y="3" width="20" height="14" rx="2" />
              <rect x="12" y="10" width="8" height="5" rx="1" fill="currentColor" stroke="none" />
            </svg>
            PiP
          </button>

          {/* Theme selector button */}
          <div style={{ position: "relative" }}>
            <button
              onClick={() => setShowThemeSelector(!showThemeSelector)}
              title="Change theme"
              style={{
                display: "flex", alignItems: "center", gap: 6,
                padding: "6px 10px", borderRadius: 6,
                background: showThemeSelector ? "rgba(var(--theme-accent),0.12)" : "transparent",
                border: `1px solid ${showThemeSelector ? "var(--ct-color)" : "var(--bg-border-dim)"}`,
                color: "var(--text-secondary)",
                fontSize: 12, fontWeight: 700, cursor: "pointer",
                fontFamily: "inherit", letterSpacing: "0.04em", transition: "all 0.15s",
              }}
              onMouseEnter={e => { if (!showThemeSelector) { e.currentTarget.style.borderColor = "var(--bg-border)"; e.currentTarget.style.color = "var(--text-primary)"; }}}
              onMouseLeave={e => { if (!showThemeSelector) { e.currentTarget.style.borderColor = "var(--bg-border-dim)"; e.currentTarget.style.color = "var(--text-secondary)"; }}}
            >
              <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                <circle cx="12" cy="12" r="5" />
                <path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" />
              </svg>
              <span style={{
                width: 10, height: 10, borderRadius: "50%",
                background: currentThemeData.accent || "var(--text-secondary)",
                boxShadow: `0 0 6px ${currentThemeData.accent || "var(--text-secondary)"}`
              }} />
            </button>

            {/* Theme dropdown */}
            {showThemeSelector && (
              <div style={{
                position: "absolute", top: "100%", right: 0, marginTop: 4,
                background: "var(--bg-panel)",
                border: "1px solid var(--bg-border)",
                borderRadius: 8,
                padding: 6,
                minWidth: 180,
                zIndex: 200,
                boxShadow: "0 8px 24px rgba(0,0,0,0.5)",
              }}>
                {availableThemes.map(theme => (
                  <button
                    key={theme.id}
                    onClick={() => handleThemeChange(theme.id)}
                    style={{
                      display: "flex", alignItems: "center", gap: 10,
                      width: "100%", padding: "8px 12px", borderRadius: 6,
                      background: currentTheme === theme.id ? "var(--bg-card-hover)" : "transparent",
                      border: currentTheme === theme.id ? "1px solid var(--bg-border)" : "1px solid transparent",
                      color: "var(--text-primary)",
                      fontSize: 12, fontWeight: 600, cursor: "pointer",
                      fontFamily: "inherit", textAlign: "left", transition: "all 0.15s",
                    }}
                    onMouseEnter={e => { e.currentTarget.style.background = "var(--bg-card-hover)"; }}
                    onMouseLeave={e => { if (currentTheme !== theme.id) e.currentTarget.style.background = "transparent"; }}
                  >
                    <span style={{
                      width: 8, height: 8, borderRadius: "50%",
                      background: theme.accent || "#888",
                      boxShadow: `0 0 4px ${theme.accent || "#888"}`
                    }} />
                    <span style={{ flex: 1 }}>{theme.name}</span>
                    {currentTheme === theme.id && (
                      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="var(--ct-color)" strokeWidth="3">
                        <polyline points="20 6 9 17 4 12" />
                      </svg>
                    )}
                  </button>
                ))}
              </div>
            )}
          </div>
        </div>

        {/* Settings / Latency */}
        <Latency value={averageLatency} settings={settings} setSettings={setSettings} />
      </div>

      {/* ── Main content ─────────────────────────────────────────────────────── */}
      <div className="flex-1 overflow-y-auto overflow-x-hidden" style={{ padding: isMobile ? "12px" : "16px 20px" }}>

        {playerArray.length > 0 && mapData ? (
          <>
            {/* ── Mobile layout ─────────────────────────────────────────────── */}
            {isMobile && (
              <div className="flex flex-col gap-3">
                <div style={{ display: "flex", gap: 6 }}>
                  {[
                    { key: "t",  label: `Terrorists (${terrorists.length})`,  color: "var(--t-color)",  border: "var(--t-border)",  bg: "var(--t-dim)"  },
                    { key: "ct", label: `CT (${counterTerrorists.length})`,   color: "var(--ct-color)", border: "var(--ct-border)", bg: "var(--ct-dim)" },
                  ].map(({ key, label, color, border, bg }) => (
                    <button
                      key={key}
                      onClick={() => setShowTeamList(showTeamList === key ? "none" : key)}
                      style={{
                        flex: 1, padding: "8px 12px", borderRadius: 6,
                        border: `1px solid ${showTeamList === key ? border : "var(--bg-border-dim)"}`,
                        background: showTeamList === key ? bg : "transparent",
                        color: showTeamList === key ? color : "var(--text-secondary)",
                        fontSize: 11, fontWeight: 800, letterSpacing: "0.1em",
                        textTransform: "uppercase", cursor: "pointer", fontFamily: "inherit",
                      }}
                    >
                      {label}
                    </button>
                  ))}
                </div>

                {showTeamList === "t" && showTCards && (
                  <ul style={{ listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 3 }}>
                    {terrorists.map(p => <PlayerCard key={p.m_idx} isOnRightSide={false} playerData={p} settings={settings} />)}
                  </ul>
                )}
                {showTeamList === "ct" && showCTCards && (
                  <ul style={{ listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 3 }}>
                    {counterTerrorists.map(p => <PlayerCard key={p.m_idx} isOnRightSide={true} playerData={p} settings={settings} />)}
                  </ul>
                )}

                <RadarColumn
                  roundInfo={roundInfo} localTeam={localTeam} playerArray={playerArray}
                  mapData={mapData} averageLatency={averageLatency} bombData={bombData}
                  grenadeArray={grenadeArray} droppedWeaponArray={droppedWeaponArray}
                  settings={settings} setSettings={setSettings}
                />
              </div>
            )}

            {/* ── Desktop layout ────────────────────────────────────────────── */}
            {!isMobile && (
              <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 10, maxWidth: 1560, margin: "0 auto", width: "100%" }}>

                {/* Scoreboard — centred above all columns */}
                <Scoreboard roundInfo={roundInfo} localTeam={localTeam} bombData={bombData} settings={settings} tScore={tScore} ctScore={ctScore} />

                {/* 3-column row */}
                <div style={{ display: "flex", flexDirection: "row", alignItems: "flex-start", justifyContent: "center", gap: 14, width: "100%" }}>

                  {/* T side */}
                  {showTCards && (
                    <div style={{ width: 300, flexShrink: 0 }}>
                      <div style={{
                        display: "flex", alignItems: "center", gap: 6,
                        paddingBottom: 8, marginBottom: 6,
                        borderBottom: "1px solid rgba(245,166,35,0.18)",
                      }}>
                        <div style={{ width: 6, height: 6, borderRadius: "50%", background: "var(--t-color)", boxShadow: "0 0 7px var(--t-color)", flexShrink: 0 }} />
                        <span style={{ fontSize: 9, fontWeight: 800, letterSpacing: "0.18em", color: "var(--t-color)", textTransform: "uppercase" }}>
                          Terrorists
                        </span>
                      </div>
                      <ul style={{ listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 3 }}>
                        {terrorists.map(p => <PlayerCard key={p.m_idx} isOnRightSide={false} playerData={p} settings={settings} />)}
                      </ul>
                    </div>
                  )}

                  {/* Radar centre */}
                  <RadarColumn
                    roundInfo={roundInfo} localTeam={localTeam} playerArray={playerArray}
                    mapData={mapData} averageLatency={averageLatency} bombData={bombData}
                    grenadeArray={grenadeArray} droppedWeaponArray={droppedWeaponArray}
                    settings={settings} setSettings={setSettings}
                    lockedPlayerIdx={lockedPlayerIdx} setLockedPlayerIdx={setLockedPlayerIdx}
                  />

                  {/* CT side */}
                  {showCTCards && (
                    <div style={{ width: 300, flexShrink: 0 }}>
                      <div style={{
                        display: "flex", alignItems: "center", justifyContent: "flex-end", gap: 6,
                        paddingBottom: 8, marginBottom: 6,
                        borderBottom: "1px solid rgba(74,158,255,0.18)",
                      }}>
                        <span style={{ fontSize: 9, fontWeight: 800, letterSpacing: "0.18em", color: "var(--ct-color)", textTransform: "uppercase" }}>
                          Counter-Terrorists
                        </span>
                        <div style={{ width: 6, height: 6, borderRadius: "50%", background: "var(--ct-color)", boxShadow: "0 0 7px var(--ct-color)", flexShrink: 0 }} />
                      </div>
                      <ul style={{ listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 3 }}>
                        {counterTerrorists.map(p => <PlayerCard key={p.m_idx} isOnRightSide={true} playerData={p} settings={settings} />)}
                      </ul>
                    </div>
                  )}

                </div>
              </div>
            )}
          </>
        ) : (
          /* ── Connecting screen ──────────────────────────────────────────── */
          <div className="h-full flex flex-col items-center justify-center gap-5 p-4">
            <div className="connecting-ring" />
            <div style={{ textAlign: "center" }}>
              <div style={{ fontSize: 11, fontWeight: 800, letterSpacing: "0.22em", color: "var(--text-secondary)", textTransform: "uppercase", marginBottom: 6 }}>
                Connecting
              </div>
              <p style={{ fontSize: 12, color: "var(--text-muted)", maxWidth: 340 }}>
                Waiting for CS2 game data...
              </p>
            </div>
            <span className="radar_message" style={{ fontSize: 11, color: "var(--hp-low)", maxWidth: 400, textAlign: "center" }} />
          </div>
        )}

      </div>
    </div>
    {showShareModal && <ShareModal onClose={() => setShowShareModal(false)} />}
    {showChooseSelfModal && (
      <ChooseSelfModal
        playerArray={playerArray}
        localTeam={localTeam}
        onSelect={handleChooseSelf}
        onSkip={handleSkipChooseSelf}
      />
    )}
    {pipOpen && (
      <PipWindow
        playerArray={playerArray}
        mapData={mapData}
        bombData={bombData}
        grenadeArray={grenadeArray}
        droppedWeaponArray={droppedWeaponArray}
        localTeam={localTeam}
        averageLatency={averageLatency}
        settings={settings}
        roundInfo={roundInfo}
        lockedPlayerIdx={lockedPlayerIdx}
        followYourselfRotation={settings.followYourselfRotation ?? false}
        onClose={() => setPipOpen(false)}
      />
    )}
    </>
  );
};

export default App;