// SEIS+ Internals — main app.

const { SectionHead, Pill } = window.SEIS_PRIM;
const { LiteLLMBudget, ModelRanking, EC2Budget, ActiveServers, EC2History, Shortcuts, ActivityFeed, YourInstances } = window.SEIS_MODULES;
const { EC2Launcher } = window.SEIS_LAUNCHER;
const { InstancePanel } = window.SEIS_INSTANCE_PANEL;
const { TweaksPanel, useTweaks, TweakSection, TweakRadio, TweakSelect, TweakToggle } = window;
const { LoginScreen, RegisterScreen } = window.SEIS_LOGIN;
const { useApi } = window.SEIS_API;
const { SHORTCUTS } = window.SEIS_STATIC;

const DEFAULTS = /*EDITMODE-BEGIN*/{
  "density": "default",
  "theme": "light",
  "accent": "sky",
  "showGrain": true
}/*EDITMODE-END*/;

const ACCENTS = {
  sky:   "oklch(58% .18 245)",
  flag:  "oklch(70% .17 132)",
  amber: "oklch(70% .15 75)",
  ink:   "var(--ink)",
};

function SshKeyPanel({ user, onRefresh }) {
  const [pubKey,     setPubKey]     = React.useState("");
  const [generating, setGenerating] = React.useState(false);
  const [msg,        setMsg]        = React.useState("");
  const [replacing,  setReplacing]  = React.useState(false);

  const handleGenerate = async () => {
    setGenerating(true); setMsg("");
    try {
      const r = await fetch("/api/auth/ssh-key/generate", { method: "POST", credentials: "include" });
      if (!r.ok) { const b = await r.json().catch(() => ({})); setMsg(b.detail || "Generate failed"); return; }
      await r.json();
      setMsg("Key generated. Download the private key below.");
      setReplacing(false);
      if (onRefresh) onRefresh();
    } catch { setMsg("Network error"); }
    finally { setGenerating(false); }
  };

  const handleUpload = async () => {
    if (!pubKey.trim()) { setMsg("Paste your public key first"); return; }
    setMsg("");
    try {
      const r = await fetch("/api/auth/ssh-key", { method: "PUT", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ publicKey: pubKey.trim() }) });
      if (!r.ok) { const b = await r.json().catch(() => ({})); setMsg(b.detail || "Upload failed"); return; }
      setMsg("Key saved."); setReplacing(false); setPubKey("");
      if (onRefresh) onRefresh();
    } catch { setMsg("Network error"); }
  };

  const handleDownload = async () => {
    try {
      const r = await fetch("/api/auth/ssh-key/download", { credentials: "include" });
      if (!r.ok) { setMsg("No generated key on file. Generate one first."); return; }
      const blob = await r.blob();
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a"); a.href = url;
      a.download = `seis-${user.handle}-rsa.pem`; a.click();
      URL.revokeObjectURL(url);
    } catch { setMsg("Download failed"); }
  };

  const hasKey = user?.hasSshKey;

  return (
    <div className="panel" style={{ marginTop: 16 }}>
      <div className="panel-head">
        <span className="idx">EC2-005</span>
        <span className="title">SSH ACCESS KEY</span>
        <span className="right">
          {hasKey
            ? <span style={{ color: "var(--ok)" }}>● RSA-4096</span>
            : <span style={{ color: "var(--warn)" }}>⚠ NOT SET</span>}
        </span>
      </div>
      <div className="panel-body">
        {hasKey && !replacing ? (
          <div>
            <div className="tiny" style={{ color: "var(--muted)", marginBottom: 12 }}>
              Key injected into instances via cloud-init. Connect with{" "}
              <code style={{ background: "var(--bg-2)", padding: "1px 5px" }}>ssh ubuntu@&lt;ip&gt;</code>.
            </div>
            <div className="row gap-8">
              <button className="btn ghost" style={{ fontSize: 9 }} onClick={handleDownload}>DOWNLOAD .PEM</button>
              <button className="btn ghost" style={{ fontSize: 9 }} onClick={() => { setReplacing(true); setPubKey(""); setMsg(""); }}>REPLACE</button>
            </div>
          </div>
        ) : (
          <div>
            {hasKey && <div className="micro" style={{ color: "var(--muted)", marginBottom: 10 }}>Replace existing key:</div>}
            <div style={{ marginBottom: 8 }}>
              <button className="btn solid" style={{ fontSize: 9, width: "100%", justifyContent: "center", opacity: generating ? 0.4 : 1 }}
                disabled={generating} onClick={handleGenerate}>
                {generating ? "GENERATING..." : "+ GENERATE RSA-4096 KEY"}
              </button>
            </div>
            <div className="micro" style={{ color: "var(--muted)", textAlign: "center", marginBottom: 8 }}>OR PASTE PUBLIC KEY</div>
            <div style={{ marginBottom: 8 }}>
              <input type="text" value={pubKey} onChange={e => setPubKey(e.target.value)}
                placeholder="ssh-rsa AAAA..." style={{ width: "100%", fontSize: 10 }} />
            </div>
            <div className="row gap-8">
              <button className="btn solid" style={{ fontSize: 9 }} onClick={handleUpload} disabled={!pubKey.trim()}>SAVE KEY</button>
              {replacing && <button className="btn ghost" style={{ fontSize: 9 }} onClick={() => { setReplacing(false); setMsg(""); }}>CANCEL</button>}
            </div>
          </div>
        )}
        {msg && <div className="micro" style={{ color: "var(--muted)", marginTop: 8 }}>{msg}</div>}
      </div>
    </div>
  );
}

function InviteButton() {
  const [msg, setMsg] = React.useState("");
  const generate = async () => {
    try {
      const r = await fetch("/api/auth/register-link", { method: "POST", credentials: "include" });
      if (!r.ok) { setMsg("FAILED"); return; }
      const d = await r.json();
      await navigator.clipboard.writeText(d.url);
      setMsg("LINK COPIED");
      setTimeout(() => setMsg(""), 2000);
    } catch {
      setMsg("ERROR");
      setTimeout(() => setMsg(""), 2000);
    }
  };
  return (
    <span className="row gap-4" style={{ alignItems: "center" }}>
      <button onClick={generate} className="micro" style={{ cursor: "pointer", color: "var(--accent)", letterSpacing: "0.14em" }}>+ INVITE</button>
      {msg && <span className="micro" style={{ color: "var(--ok)" }}>{msg}</span>}
    </span>
  );
}

function Topbar({ user, onSignOut, theme, onToggleTheme }) {
  return (
    <div className="topbar" style={{ gridTemplateColumns: "auto 1fr auto" }}>
      <span>SEIS+ INTERNALS · STUDIO ONLY</span>
      <span></span>
      <span className="row gap-12" style={{ alignItems: "center" }}>
        <button
          onClick={onToggleTheme}
          title={theme === "dark" ? "switch to day" : "switch to night"}
          aria-label="toggle theme"
          style={{
            cursor: "pointer", color: "var(--ink)", fontSize: 16, lineHeight: 1,
            padding: "2px 6px", border: "1px solid var(--rule-soft)", borderRadius: 999,
            transition: "border-color 120ms",
          }}
          onMouseEnter={e => e.currentTarget.style.borderColor = "var(--ink)"}
          onMouseLeave={e => e.currentTarget.style.borderColor = "var(--rule-soft)"}
        >
          {theme === "dark" ? "☼" : "☽"}
        </button>
        <InviteButton />
        <span style={{ color: "var(--ink)" }}>@{user.handle}</span>
        <span style={{ color: "var(--muted)", textTransform: "none", letterSpacing: "0.04em" }}>—</span>
        <span style={{ color: "var(--ink-2)", textTransform: "none", letterSpacing: "0.02em" }}>{user.name || user.handle}</span>
        <button onClick={onSignOut} className="micro" style={{ cursor: "pointer", color: "var(--muted)", letterSpacing: "0.14em" }}>SIGN OUT ↩</button>
      </span>
    </div>
  );
}

function Masthead() {
  return (
    <header style={{ padding: "28px 0 18px", borderBottom: "1px solid var(--ink)" }}>
      <div style={{
        fontFamily: "var(--mono)", fontWeight: 700,
        fontSize: "clamp(36px, 5vw, 64px)",
        lineHeight: 0.95, letterSpacing: "-0.02em",
      }}>
        INTERNALS<span style={{ color: "var(--accent)" }}>+</span>
        <span style={{ fontFamily: "var(--serif)", fontStyle: "italic", fontWeight: 300, color: "var(--muted)", marginLeft: 18, fontSize: "0.5em", letterSpacing: 0 }}>
          studio operations.
        </span>
      </div>
    </header>
  );
}

function Footer() {
  return (
    <footer style={{ marginTop: 60, borderTop: "1px solid var(--ink)", paddingTop: 18, fontSize: 10, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--muted)" }}>
      <div className="row between">
        <span>© SEIS PLUS LLC · INTERNAL TOOLING</span>
        <span>SECTION § INDEX · LIT · MDL · EC2 · HST · LNK · LOG</span>
        <span>BUILT WITH CARE · {new Date().getFullYear()}</span>
      </div>
    </footer>
  );
}

const PROBE_REGIONS = ["us-east-1", "us-east-2", "us-west-1", "us-west-2"];
const PROBE_SAMPLES = 10;
const PROBE_INTERVAL = 2000;

function App() {
  const [tweaks, setTweak] = useTweaks(DEFAULTS);
  const [launcherOpen, setLauncherOpen] = React.useState(false);
  const [instancePanelId, setInstancePanelId] = React.useState(null);
  const [user, setUser]   = React.useState(null);
  const [authLoading, setAuthLoading] = React.useState(true);
  const [authMode, setAuthMode] = React.useState(window.location.pathname.startsWith("/register") ? "register" : "login");
  const [regionLatency, setRegionLatency] = React.useState({}); // { region: [ms, ...] }

  // Session check on mount
  React.useEffect(() => {
    fetch("/api/auth/me", { credentials: "include" })
      .then(r => r.ok ? r.json() : null)
      .then(u => { setUser(u); setAuthLoading(false); })
      .catch(() => setAuthLoading(false));
  }, []);

  // Sync auth mode with URL on popstate
  React.useEffect(() => {
    const handler = () => setAuthMode(window.location.pathname.startsWith("/register") ? "register" : "login");
    window.addEventListener("popstate", handler);
    return () => window.removeEventListener("popstate", handler);
  }, []);

  // Latency probes — start on mount, 10 samples per region, every 2s
  React.useEffect(() => {
    const probe = async (reg) => {
      const t0 = performance.now();
      try { await fetch(`https://dynamodb.${reg}.amazonaws.com`, { mode: "no-cors", cache: "no-cache" }); } catch {}
      const ms = Math.round(performance.now() - t0);
      setRegionLatency(prev => {
        const s = prev[reg] || [];
        if (s.length >= PROBE_SAMPLES) return prev;
        return { ...prev, [reg]: [...s, ms] };
      });
    };

    // Stagger initial burst
    PROBE_REGIONS.forEach((reg, i) => setTimeout(() => probe(reg), i * 150));

    const id = setInterval(() => {
      setRegionLatency(snap => {
        const allDone = PROBE_REGIONS.every(r => (snap[r] || []).length >= PROBE_SAMPLES);
        if (allDone) { clearInterval(id); return snap; }
        PROBE_REGIONS.forEach((reg, i) => {
          if ((snap[reg] || []).length < PROBE_SAMPLES) setTimeout(() => probe(reg), i * 150);
        });
        return snap;
      });
    }, PROBE_INTERVAL);

    return () => clearInterval(id);
  }, []);

  // Theme / density
  React.useEffect(() => {
    document.documentElement.dataset.theme   = tweaks.theme;
    document.documentElement.dataset.density = tweaks.density;
    document.documentElement.style.setProperty("--accent", ACCENTS[tweaks.accent] || ACCENTS.sky);
  }, [tweaks]);

  React.useEffect(() => {
    const id = "grain-toggle-style";
    let el = document.getElementById(id);
    if (!el) { el = document.createElement("style"); el.id = id; document.head.appendChild(el); }
    el.textContent = tweaks.showGrain ? "" : "body::before { display: none; }";
  }, [tweaks.showGrain]);

  // Live data — only fetch when authenticated
  const [llmData,      llmLoading]  = useApi(user ? "/api/litellm/budgets" : null, 30000);
  const [ec2Budget,    budgetLoading] = useApi(user ? "/api/ec2/budget"     : null, 300000);
  const [ec2Instances, instLoading]  = useApi(user ? "/api/ec2/instances"   : null, 30000);
  const [ec2Types]                   = useApi(user ? "/api/ec2/types"        : null, 300000);
  const [activity,     actLoading]   = useApi(user ? "/api/activity"         : null, 30000);
  const [ec2History,   histLoading]  = useApi(user ? "/api/ec2/history"      : null, 60000);

  if (authLoading) {
    return (
      <div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100vh", fontFamily: "var(--mono)", fontSize: 11, letterSpacing: "0.14em", color: "var(--muted)" }}>
        AUTHENTICATING...
      </div>
    );
  }

  const switchAuthMode = (mode) => {
    const path = mode === "register" ? "/register" : "/login";
    window.history.pushState({}, "", path);
    setAuthMode(mode);
  };

  const registerTokenMatch = window.location.pathname.match(/^\/register\/(.+)$/);
  const registerToken = registerTokenMatch ? registerTokenMatch[1] : "";

  if (!user) {
    if (authMode === "register") {
      return <RegisterScreen
        onAuth={(m) => setUser(m)}
        theme={tweaks.theme}
        onToggleTheme={() => setTweak("theme", tweaks.theme === "dark" ? "light" : "dark")}
        onSwitchMode={switchAuthMode}
        registerToken={registerToken}
      />;
    }
    return <LoginScreen
      onAuth={(m) => setUser(m)}
      theme={tweaks.theme}
      onToggleTheme={() => setTweak("theme", tweaks.theme === "dark" ? "light" : "dark")}
      onSwitchMode={switchAuthMode}
    />;
  }

  const signOut = () => {
    fetch("/api/auth/logout", { method: "POST", credentials: "include" })
      .finally(() => setUser(null));
  };

  const budgets = llmData?.budgets || [];
  const models  = llmData?.models  || [];

  return (
    <div className="shell">
      <Topbar user={user} onSignOut={signOut} theme={tweaks.theme} onToggleTheme={() => setTweak("theme", tweaks.theme === "dark" ? "light" : "dark")} />
      <Masthead />

      {/* §01 — AI & GPUs */}
      <section className="section">
        <SectionHead num="01" title="AI & GPUs" sub="live spend across models + cloud" right="APR 2026" />
        <div className="grid" style={{ gridTemplateColumns: "1.5fr 1fr", marginTop: 16, alignItems: "start" }}>
          <LiteLLMBudget budgets={budgets} models={models} loading={llmLoading} />
          <div>
            <EC2Budget budget={ec2Budget} loading={budgetLoading} onLaunch={() => setLauncherOpen(true)} />
            <SshKeyPanel user={user} onRefresh={() => {
              fetch("/api/auth/me", { credentials: "include" }).then(r => r.ok ? r.json() : null).then(u => u && setUser(u));
            }} />
            <YourInstances instances={ec2Instances || []} instanceTypes={ec2Types || []} userHandle={user.handle} onOpenInstance={id => setInstancePanelId(id)} hasSshKey={user?.hasSshKey} />
          </div>
        </div>
      </section>

      {/* §02 — MODELS */}
      <section className="section">
        <SectionHead num="02" title="MODELS" sub="intelligence ranking & token reserve" right="POLL · 30S" />
        <div style={{ marginTop: 16 }}>
          <ModelRanking models={models} loading={llmLoading} />
        </div>
      </section>

      {/* §03 — SERVERS */}
      <section className="section">
        <SectionHead num="03" title="SERVERS" sub="active EC2 spot fleet" right={ec2Instances ? `${ec2Instances.length} LIVE` : "—"} />
        <div style={{ marginTop: 16 }}>
          <ActiveServers instances={ec2Instances || []} loading={instLoading}
            onOpenInstance={id => setInstancePanelId(id)}
            hasSshKey={user?.hasSshKey} />
        </div>
      </section>

      {/* §04 — EC2 HISTORY */}
      <section className="section">
        <SectionHead num="04" title="EC2 HISTORY" sub="spot launch log · cost tracking" right="POLL · 60S" />
        <div style={{ marginTop: 16 }}>
          <EC2History history={ec2History || []} loading={histLoading} />
        </div>
      </section>

      {/* §05 — SHORTCUTS */}
      <section className="section">
        <SectionHead num="05" title="ATAJOS" sub="herramientas internas" right="STUDIO LINKS" />
        <div style={{ marginTop: 16 }}>
          <Shortcuts shortcuts={SHORTCUTS} />
        </div>
      </section>

      {/* §06 — ACTIVITY */}
      <section className="section">
        <SectionHead num="06" title="ACTIVITY" sub="spawns · merges · deploys" right="REAL-TIME" />
        <div style={{ marginTop: 16 }}>
          <ActivityFeed activity={activity || []} loading={actLoading} />
        </div>
      </section>

      <Footer />

      <EC2Launcher
        open={launcherOpen}
        onClose={() => setLauncherOpen(false)}
        instanceTypes={ec2Types || []}
        budget={ec2Budget}
        regionLatency={regionLatency}
      />

      {instancePanelId && (
        <InstancePanel
          instanceId={instancePanelId}
          onClose={() => setInstancePanelId(null)}
          hasSshKey={user?.hasSshKey}
          user={user}
        />
      )}


      <TweaksPanel title="Tweaks">
        <TweakSection title="Density">
          <TweakRadio
            value={tweaks.density}
            onChange={v => setTweak("density", v)}
            options={[
              { value: "compact",  label: "Compact" },
              { value: "default",  label: "Default" },
              { value: "spacious", label: "Spacious" },
            ]}
          />
        </TweakSection>
        <TweakSection title="Theme">
          <TweakRadio
            value={tweaks.theme}
            onChange={v => setTweak("theme", v)}
            options={[
              { value: "light", label: "Cream" },
              { value: "dark",  label: "Dark"  },
            ]}
          />
        </TweakSection>
        <TweakSection title="Accent">
          <TweakSelect
            value={tweaks.accent}
            onChange={v => setTweak("accent", v)}
            options={[
              { value: "sky",   label: "Sky (brand)" },
              { value: "flag",  label: "Flag green"  },
              { value: "amber", label: "Amber"        },
              { value: "ink",   label: "Ink (mono)"  },
            ]}
          />
        </TweakSection>
        <TweakSection title="Texture">
          <TweakToggle
            checked={tweaks.showGrain}
            onChange={v => setTweak("showGrain", v)}
            label="Paper grain overlay"
          />
        </TweakSection>
      </TweaksPanel>
    </div>
  );
}

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