/* ============================================================
   app.jsx — LIVE PWA shell. Fetches /api/dashboard (the window.OCC
   contract computed by the backend), gates behind the Argon2id
   session, and shows a data-source banner (sample / live / building).
   The design-time demo-scenario switcher and tweaks panel are removed:
   the dashboard now reflects real computed values only.
   Screens (Home/Recovery/Sleep/Trends/Clinical) and primitives are
   loaded unchanged from the design files.
   ============================================================ */
(function () {
  const { useState, useEffect, useCallback } = React;
  const ACCENT = { good: 132, attn: 352, acute: 18 }; // fixed "Sage / Plum"

  function api(path, opts = {}) {
    return fetch(path, Object.assign(
      { credentials: "same-origin", headers: { "Content-Type": "application/json" } }, opts));
  }

  // ---- device chrome (unchanged from the design) ----------
  function StatusBar() {
    return (
      <div className="phone-status">
        <span className="num" style={{ fontSize: 12.5, fontWeight: 600 }}>6:42</span>
        <span style={{ display: "inline-flex", gap: 6, alignItems: "center", opacity: 0.85 }}>
          <svg width="17" height="11" viewBox="0 0 17 11"><g fill="currentColor">{[0,1,2,3].map(i=><rect key={i} x={i*4.4} y={8-i*2.4} width="3" height={3+i*2.4} rx="0.5"/>)}</g></svg>
          <svg width="24" height="11" viewBox="0 0 24 11"><rect x="0.5" y="0.5" width="20" height="10" rx="2.5" fill="none" stroke="currentColor" strokeOpacity="0.5"/><rect x="2" y="2" width="15" height="7" rx="1.2" fill="currentColor"/></svg>
        </span>
      </div>
    );
  }

  function AppBar({ route, go, theme, toggleTheme, onLogout }) {
    const detail = route.screen === "recovery" || route.screen === "sleep";
    return (
      <header className="appbar">
        {detail ? (
          <button onClick={() => go("home")} style={btn()}>
            <Icon name="back" size={20} color="var(--ink-2)" />
            <span style={{ fontSize: 15, fontWeight: 600, textTransform: "capitalize" }}>{route.screen}</span>
          </button>
        ) : (
          <div style={{ display: "flex", alignItems: "center", gap: 9 }}>
            <span style={{ width: 18, height: 18, borderRadius: 5, background: "var(--ink)", display: "grid", placeItems: "center" }}>
              <span style={{ width: 7, height: 7, borderRadius: 999, border: "1.6px solid var(--surface)" }} />
            </span>
            <span style={{ fontSize: 14.5, letterSpacing: "-0.01em" }}><b style={{ fontWeight: 700 }}>openclaw</b><span style={{ color: "var(--ink-3)" }}>clinic</span></span>
          </div>
        )}
        <div style={{ display: "flex", gap: 8 }}>
          <button onClick={toggleTheme} aria-label="toggle theme" style={iconBtn()}>
            <Icon name={theme === "dark" ? "sun" : "moon"} size={17} color="var(--ink-2)" />
          </button>
          <button onClick={onLogout} aria-label="sign out" style={iconBtn()}>
            <svg width="17" height="17" viewBox="0 0 20 20" fill="none" stroke="var(--ink-2)" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
              <path d="M8 4 H5 a1 1 0 0 0 -1 1 V15 a1 1 0 0 0 1 1 H8" /><path d="M12 13 L16 10 L12 7" /><line x1="16" y1="10" x2="8" y2="10" />
            </svg>
          </button>
        </div>
      </header>
    );
  }

  function TabBar({ route, go, alert }) {
    const tabs = [["home", "Home", "home"], ["trends", "Trends", "trend"], ["clinical", "Clinical", "clinical"]];
    const activeTab = ["recovery", "sleep"].includes(route.screen) ? "home" : route.screen;
    return (
      <nav className="tabbar">
        {tabs.map(([k, label, icon]) => {
          const on = activeTab === k;
          return (
            <button key={k} onClick={() => go(k)} style={{ flex: 1, background: "none", border: "none", display: "flex", flexDirection: "column", alignItems: "center", gap: 4, color: on ? "var(--ink)" : "var(--ink-4)", position: "relative", padding: "6px 0" }}>
              <Icon name={icon} size={21} color={on ? "var(--ink)" : "var(--ink-4)"} />
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 9.5, letterSpacing: "0.04em", fontWeight: 500 }}>{label}</span>
              {k === "clinical" && alert && <span style={{ position: "absolute", top: 4, right: "calc(50% - 16px)", width: 6, height: 6, borderRadius: 999, background: alert === "acute" ? "var(--acute)" : "var(--attn)" }} />}
            </button>);
        })}
      </nav>
    );
  }

  // ---- data-source banner (sample / live / building) ------
  function SourceBanner({ ds }) {
    if (!ds) return null;
    const tone = ds.mode === "live" ? "var(--good)" : ds.mode === "building" ? "var(--attn)" : "var(--ink-3)";
    const label = { live: "LIVE", building: `BASELINE BUILDING · ${ds.nights_valid}/${ds.baseline_target}`,
                    sample: "SAMPLE DATA", none: "NO DATA" }[ds.mode] || ds.mode;
    return (
      <div style={{ display: "flex", alignItems: "center", gap: 9, padding: "7px 14px", borderBottom: "1px solid var(--line)", background: "var(--bg-sunken)" }}>
        <span style={{ flexShrink: 0, fontFamily: "var(--font-mono)", fontSize: 9.5, fontWeight: 600, letterSpacing: "0.05em",
                       color: tone, border: `1px solid ${tone}`, borderRadius: 999, padding: "2px 8px" }}>{label}</span>
        <span style={{ fontSize: 11, color: "var(--ink-3)", lineHeight: 1.3, textWrap: "pretty" }}>{ds.note}</span>
      </div>
    );
  }

  // ---- login (styled with tokens) -------------------------
  function Login({ onLogin }) {
    const [u, setU] = useState(""); const [p, setP] = useState("");
    const [err, setErr] = useState(null); const [busy, setBusy] = useState(false);
    const submit = async (e) => {
      e.preventDefault(); setBusy(true); setErr(null);
      try {
        const r = await api("/api/auth/login", { method: "POST", body: JSON.stringify({ username: u, password: p }) });
        if (r.ok) { onLogin(); return; }
        const d = await r.json().catch(() => ({}));
        setErr(r.status === 429 ? "Too many attempts — locked out briefly." : (d.detail || "Invalid credentials"));
      } catch (e) { setErr("Network error"); } finally { setBusy(false); }
    };
    return (
      <div style={{ flex: 1, display: "grid", placeItems: "center", padding: 24 }}>
        <form onSubmit={submit} style={{ width: "100%", maxWidth: 320, display: "flex", flexDirection: "column", gap: 12 }}>
          <div style={{ textAlign: "center", marginBottom: 8 }}>
            <div style={{ fontSize: 18, fontWeight: 700 }}><b>openclaw</b><span style={{ color: "var(--ink-3)" }}>clinic</span></div>
            <div className="mono-label" style={{ color: "var(--ink-4)", marginTop: 4 }}>SIGN IN</div>
          </div>
          <input value={u} onChange={(e) => setU(e.target.value)} placeholder="username" autoComplete="username" style={inp()} />
          <input value={p} onChange={(e) => setP(e.target.value)} placeholder="password" type="password" autoComplete="current-password" style={inp()} />
          {err && <div style={{ color: "var(--acute-ink)", fontSize: 12.5 }}>{err}</div>}
          <button type="submit" disabled={busy} style={{ ...inp(), background: "var(--ink)", color: "var(--bg)", fontWeight: 600, cursor: "pointer", borderColor: "var(--ink)" }}>
            {busy ? "…" : "Sign in"}
          </button>
        </form>
      </div>
    );
  }

  const Center = ({ children }) => (
    <div style={{ flex: 1, display: "grid", placeItems: "center", color: "var(--ink-3)", padding: 24, textAlign: "center" }}>{children}</div>
  );

  function App() {
    const [theme, setTheme] = useState(() => localStorage.getItem("occ-theme") || "light");
    const [authed, setAuthed] = useState(null);    // null=checking
    const [dash, setDash] = useState(null);
    const [err, setErr] = useState(null);
    const [route, setRoute] = useState({ screen: "home", param: null });

    useEffect(() => { document.documentElement.dataset.theme = theme; localStorage.setItem("occ-theme", theme); }, [theme]);
    useEffect(() => {
      const r = document.documentElement.style;
      r.setProperty("--good-h", ACCENT.good); r.setProperty("--attn-h", ACCENT.attn); r.setProperty("--acute-h", ACCENT.acute);
    }, []);

    const loadDash = useCallback(async () => {
      try {
        const r = await api("/api/dashboard");
        if (r.status === 401) { setAuthed(false); return; }
        setDash(await r.json());
      } catch (e) { setErr(String(e)); }
    }, []);

    useEffect(() => {
      (async () => {
        try { const r = await api("/api/auth/me"); if (r.ok) { setAuthed(true); loadDash(); } else setAuthed(false); }
        catch (e) { setAuthed(false); }
      })();
    }, [loadDash]);

    const go = (screen, param = null) => { setRoute({ screen, param }); document.querySelector(".screen")?.scrollTo(0, 0); };
    const logout = async () => { await api("/api/auth/logout", { method: "POST" }); setAuthed(false); setDash(null); setRoute({ screen: "home", param: null }); };
    const toggleTheme = () => setTheme((x) => x === "dark" ? "light" : "dark");

    const frame = (children) => (
      <div className="stage"><div className="phone"><div className="device-screen">{children}</div></div></div>
    );

    if (authed === null) return frame(<><StatusBar /><Center>Loading…</Center></>);
    if (authed === false) return frame(<><StatusBar /><Login onLogin={() => { setAuthed(true); loadDash(); }} /></>);
    if (err) return frame(<><StatusBar /><Center>Couldn’t load data.<br />{err}</Center></>);
    if (!dash) return frame(<><StatusBar /><Center>Loading your data…</Center></>);

    if (!dash.available) {
      return frame(<>
        <StatusBar />
        <AppBar route={route} go={go} theme={theme} toggleTheme={toggleTheme} onLogout={logout} />
        <SourceBanner ds={dash.data_source} />
        <Center><div>
          <div style={{ fontSize: 16, fontWeight: 600, color: "var(--ink)", marginBottom: 8 }}>No data yet</div>
          <div style={{ fontSize: 13 }}>{dash.data_source?.note}</div>
        </div></Center>
      </>);
    }

    // expose the live contract for screens that read globals
    window.OCC = { trends: dash.trends, clinicalFor: () => dash.clinical };
    const data = dash.scenario;
    const alert = (data.acute || []).length ? "acute" : (data.subacute || []).length ? "attn" : null;

    let body;
    if (route.screen === "home") body = <Home data={data} go={go} viz="dist" layout="stack" />;
    else if (route.screen === "recovery") body = <Recovery data={data} viz="dist" />;
    else if (route.screen === "sleep") body = <Sleep data={data} />;
    else if (route.screen === "trends") body = <Trends data={data} />;
    else if (route.screen === "clinical") body = <Clinical data={data} initial={route.param || "af"} />;

    return (
      <div className="stage">
        <div className="phone">
          <div className="device-screen">
            <StatusBar />
            <AppBar route={route} go={go} theme={theme} toggleTheme={toggleTheme} onLogout={logout} />
            <SourceBanner ds={dash.data_source} />
            <main className="screen" key={route.screen}><div className="screen-inner">{body}</div></main>
            <TabBar route={route} go={go} alert={alert} />
          </div>
        </div>
      </div>
    );
  }

  // small style helpers
  function btn() { return { display: "flex", alignItems: "center", gap: 7, background: "none", border: "none", color: "var(--ink)", padding: 0 }; }
  function iconBtn() { return { width: 34, height: 34, borderRadius: 999, border: "1px solid var(--line)", background: "var(--surface)", display: "grid", placeItems: "center" }; }
  function inp() { return { padding: "11px 13px", borderRadius: "var(--r-sm, 10px)", border: "1px solid var(--line)", background: "var(--surface)", color: "var(--ink)", fontSize: 14, fontFamily: "var(--font-ui)" }; }

  window.OCCApp = App;
})();
