/* app.jsx — DoomCRM root: connection (HubSpot vs demo), routing, theme vars, commit. */
const { useState: uS, useEffect: uE, useMemo: uM } = React;

// Baked-in look.
const t = {
  theme: "neon",
  titleArt: "metal",
  font: "silkscreen",
  gore: 2,
  scanlines: 0.15,
  hudLayout: "classic",
  spriteStyle: "mixed",
};

// Turn fetched HubSpot records into the game's list structure (reusing the
// humor bank from DOOMSPOT_DATA for barks/lines).
// Build the hit-list picker from the portal's real HubSpot Lists (segments),
// plus two whole-object "ALL" buckets. Members are loaded lazily on pick.
function buildLiveData(base, listsResp) {
  const real = (listsResp && listsResp.lists) || [];
  const card = (l) => {
    const isCo = l.objectType === "company";
    const sz = l.size == null ? "?" : l.size;
    return {
      id: l.id, name: (l.name || "UNTITLED LIST").toUpperCase(), objectType: l.objectType,
      kind: l.processingType === "DYNAMIC" ? "SMART LIST" : "STATIC LIST",
      owner: "your HubSpot portal",
      blurb: isCo ? "Companies in this segment. Deletion is for keeps (90-day bin)."
                  : "People in this segment. What dies in the arena dies in HubSpot.",
      members: null,
      total: sz, contacts: isCo ? 0 : sz, companies: isCo ? sz : 0,
    };
  };
  const lists = real.map(card);
  lists.push({ id: "all-contacts", name: "ALL CONTACTS", objectType: "contact", kind: "EVERYONE", owner: "your HubSpot portal", blurb: "Every contact in the portal — first 60 into the arena.", members: null, total: "ALL", contacts: "ALL", companies: 0 });
  lists.push({ id: "all-companies", name: "ALL COMPANIES", objectType: "company", kind: "EVERYONE", owner: "your HubSpot portal", blurb: "Every company in the portal — first 60 into the arena.", members: null, total: "ALL", contacts: 0, companies: "ALL" });
  return Object.assign({}, base, { lists, needsReconnect: listsResp && listsResp.needsReconnect });
}

function App() {
  const DATA = window.DOOMSPOT_DATA;
  const API = window.DOOMCRM_API;
  const track = (ev, props) => { try { if (window.DOOMCRM_TRACK) window.DOOMCRM_TRACK(ev, props || {}); } catch (e) {} };
  const theme = window.DOOMSPOT_THEMES[t.theme] || window.DOOMSPOT_THEMES.hellfire;
  const font = window.DOOMSPOT_FONTS[t.font] || window.DOOMSPOT_FONTS.pressstart;

  const [conn, setConn] = uS(null);     // null=checking, {connected, portalId, email}
  const [mode, setMode] = uS(null);     // 'live' | 'practice'
  const [liveData, setLiveData] = uS(null);
  const [loadingRecs, setLoadingRecs] = uS(false);
  const [recErr, setRecErr] = uS(null);
  const [loadingMore, setLoadingMore] = uS(false);

  const [screen, setScreen] = uS("connect");
  const [filter, setFilter] = uS("both");
  const [selectedList, setSelectedList] = uS(null);
  const [selectedIds, setSelectedIds] = uS(new Set());
  const [deleted, setDeleted] = uS([]);
  const [result, setResult] = uS(null);
  const [gameKey, setGameKey] = uS(0);
  const [toast, setToast] = uS(null);

  // theme + font -> CSS vars
  uE(() => {
    const r = document.documentElement.style;
    r.setProperty("--bg", theme.bg); r.setProperty("--panel", theme.panel); r.setProperty("--panel-edge", theme.panelEdge);
    r.setProperty("--ink", theme.ink); r.setProperty("--ink-dim", theme.inkDim);
    r.setProperty("--accent", theme.accent); r.setProperty("--accent2", theme.accent2); r.setProperty("--good", theme.good);
    r.setProperty("--blood", theme.blood); r.setProperty("--crosshair", theme.crosshair);
    r.setProperty("--font", font.stack); r.setProperty("--fscale", font.scale);
  }, [theme, font]);

  function enterLive() {
    setMode("live"); setLoadingRecs(true); setRecErr(null); setScreen("lists");
    API.lists().then(r => { setLiveData(buildLiveData(DATA, r)); setLoadingRecs(false); })
      .catch(e => { setRecErr(String(e.message || e)); setLoadingRecs(false); });
  }
  function enterPractice() { setMode("practice"); setLiveData(null); setScreen("lists"); }
  const connectHubspot = () => { track("connect_hubspot_clicked"); if (API) API.install(); };
  const playDemo = () => { track("demo_started"); enterPractice(); };

  // check HubSpot connection on load (skip if the dev shortcut is driving)
  uE(() => {
    if (!API) { setConn({ connected: false }); return; }
    if (new URLSearchParams(location.search).get("dev") === "game") return;
    API.me().then(c => { setConn(c); if (c.connected) { track("hubspot_connected", { portal_id: c.portalId }); enterLive(); } }).catch(() => setConn({ connected: false }));
    // eslint-disable-next-line
  }, []);

  // dev shortcut: /?dev=game jumps into the arena with demo data
  uE(() => {
    const p = new URLSearchParams(location.search);
    if (p.get("dev") === "game") {
      setConn({ connected: false }); setMode("practice");
      const L = DATA.lists[0];
      setSelectedList(L); setSelectedIds(new Set(L.members.map(m => m.id)));
      setDeleted([]); setResult(null); setGameKey(k => k + 1); setScreen("game");
    }
  }, []);

  const activeData = mode === "live" ? (liveData || Object.assign({}, DATA, { lists: [] })) : DATA;

  const memberById = uM(() => { const m = {}; (selectedList ? selectedList.members : []).forEach(r => { m[r.id] = r; }); return m; }, [selectedList]);
  const toggle = id => setSelectedIds(s => { const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n; });
  const selectAll = recs => setSelectedIds(s => { const n = new Set(s); recs.forEach(r => n.add(r.id)); return n; });
  const clearAll = () => setSelectedIds(new Set());
  const pickList = L => {
    setFilter("both"); setSelectedIds(new Set());
    if (mode === "live" && API && L.members == null) {
      setToast("SCANNING " + L.name + "…");
      API.members(L.id, L.objectType, null).then(r => {
        const recs = (r.records || []).map(m => Object.assign({ reason: "real record · will be archived" }, m));
        if (!recs.length) { setToast("“" + L.name + "” is empty — nothing to purge."); setTimeout(() => setToast(null), 3500); return; }
        setToast(null);
        setSelectedList(Object.assign({}, L, { members: recs, _after: r.after || null, _listId: L.id, _objectType: L.objectType }));
        setScreen("select");
      }).catch(e => { setToast("✗ " + (e.message || e)); setTimeout(() => setToast(null), 5000); });
    } else {
      setSelectedList(L); setScreen("select");
    }
  };
  const loadMore = () => {
    const L = selectedList;
    if (!L || !L._after || loadingMore || !API) return;
    setLoadingMore(true);
    API.members(L._listId, L._objectType, L._after).then(r => {
      const more = (r.records || []).map(m => Object.assign({ reason: "real record · will be archived" }, m));
      setSelectedList(prev => Object.assign({}, prev, { members: prev.members.concat(more), _after: r.after || null }));
      setLoadingMore(false);
    }).catch(e => { setToast("✗ " + (e.message || e)); setLoadingMore(false); setTimeout(() => setToast(null), 4000); });
  };
  const start = () => {
    track("game_started", { mode: mode || "practice", list: selectedList && selectedList.name, enemies: selectedIds.size });
    setDeleted([]); setResult(null); setGameKey(k => k + 1); setScreen("game");
  };
  const selectedRecords = uM(() => [...selectedIds].map(id => memberById[id]).filter(Boolean), [selectedIds, memberById]);
  const onGameOver = (reason, stats) => { setResult({ reason, stats }); setScreen("score"); };

  const onConfirm = (restoredIds) => {
    const spared = new Set(restoredIds);
    const toDelete = deleted.filter(d => !spared.has(d.id));
    if (mode === "live" && API) {
      setToast("☠ COMMITTING TO HUBSPOT…");
      API.commit(toDelete.map(d => ({ id: d.id, type: d.type })))
        .then(r => {
          track("purge_committed", { mode: "live", archived: r.deleted, spared: restoredIds.length });
          setToast("✓ COMMITTED · " + r.deleted + " archived in HubSpot · " + restoredIds.length + " spared");
          API.lists().then(r => setLiveData(buildLiveData(DATA, r))).catch(() => {});
          setSelectedIds(new Set()); setSelectedList(null); setScreen("lists");
          setTimeout(() => setToast(null), 6000);
        })
        .catch(e => { setToast("✗ COMMIT FAILED · " + (e.message || e)); setScreen("lists"); setTimeout(() => setToast(null), 6500); });
    } else {
      track("purge_committed", { mode: "practice", purged: toDelete.length, spared: restoredIds.length });
      setToast("✓ DEMO · " + toDelete.length + " purged · " + restoredIds.length + " spared (nothing real was deleted)");
      setSelectedIds(new Set()); setScreen("lists"); setTimeout(() => setToast(null), 4200);
    }
  };

  return (
    <div style={{ position: "absolute", inset: 0, background: "var(--bg)", overflow: "hidden" }}>
      {screen === "connect" && (
        <ConnectScreen titleArt={t.titleArt} conn={conn} onConnect={connectHubspot} onPractice={playDemo} />
      )}
      {screen === "lists" && (
        <ListScreen data={activeData} titleArt={t.titleArt} mode={mode} conn={conn} loading={loadingRecs} err={recErr}
          onPick={pickList} onLogout={() => API && API.logout()} onConnect={connectHubspot} />
      )}
      {screen === "select" && selectedList && (
        <SelectScreen list={selectedList} titleArt={t.titleArt} selectedIds={selectedIds} mode={mode}
          toggle={toggle} selectAll={selectAll} clearAll={clearAll}
          filter={filter} setFilter={setFilter} onStart={start} onBack={() => setScreen("lists")}
          hasMore={!!(selectedList && selectedList._after)} onLoadMore={loadMore} loadingMore={loadingMore} />
      )}
      {screen === "game" && (
        <GameScreen key={gameKey} records={selectedRecords} theme={theme} font={font}
          gore={t.gore} spriteStyle={t.spriteStyle} hudLayout={t.hudLayout}
          onKill={rec => setDeleted(d => d.find(x => x.id === rec.id) ? d : [...d, rec])}
          onGameOver={onGameOver} />
      )}
      {screen === "score" && result && (
        <ScoreScreen reason={result.reason} stats={result.stats} deleted={deleted} mode={mode}
          onConfirm={onConfirm} onReplay={() => setScreen("select")} />
      )}

      {toast && (
        <div style={{ position: "fixed", top: 22, left: "50%", transform: "translateX(-50%)", zIndex: 9500, fontFamily: "var(--font)", fontSize: "calc(9px * var(--fscale))", color: "var(--good)", background: "rgba(8,4,2,.92)", border: "2px solid var(--good)", padding: "12px 20px", letterSpacing: ".05em", boxShadow: "0 0 22px rgba(0,0,0,.6)", maxWidth: "90vw", textAlign: "center" }}>{toast}</div>
      )}

      <Scanlines intensity={t.scanlines} glow={theme.glow} />
    </div>
  );
}

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