// ─────────────────────────────────────────────────────────────────────────
// Meridian — app shell + Hermes chat engine (wired to the real API)
// Sidebar, slim top bar, the slide-out Hermes panel + floating launcher, and
// the shared chat hook that talks to POST /api/hermes/chat.
// ─────────────────────────────────────────────────────────────────────────

/* ── Tiny markdown renderer ───────────────────────────────────────────────── */
function mdInline(s) {
  s = s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  s = s.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
  s = s.replace(/`([^`]+)`/g, "<code>$1</code>");
  s = s.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" rel="noopener">$1</a>');
  s = s.replace(/\*([^*]+)\*/g, "<em>$1</em>");
  return s;
}
function md(src) {
  const lines = (src || "").split("\n");
  let html = "", list = null;
  const closeList = () => { if (list) { html += `</${list}>`; list = null; } };
  for (let raw of lines) {
    const line = raw.replace(/\s+$/, "");
    if (!line.trim()) { closeList(); continue; }
    let m;
    if ((m = line.match(/^###\s+(.*)/))) { closeList(); html += `<h3>${mdInline(m[1])}</h3>`; }
    else if ((m = line.match(/^##\s+(.*)/))) { closeList(); html += `<h2>${mdInline(m[1])}</h2>`; }
    else if ((m = line.match(/^#\s+(.*)/))) { closeList(); html += `<h1>${mdInline(m[1])}</h1>`; }
    else if ((m = line.match(/^>\s?(.*)/))) { closeList(); html += `<blockquote>${mdInline(m[1])}</blockquote>`; }
    else if ((m = line.match(/^[-*]\s+(.*)/))) { if (list !== "ul") { closeList(); list = "ul"; html += "<ul>"; } html += `<li>${mdInline(m[1])}</li>`; }
    else if ((m = line.match(/^\d+\.\s+(.*)/))) { if (list !== "ol") { closeList(); list = "ol"; html += "<ol>"; } html += `<li>${mdInline(m[1])}</li>`; }
    else { closeList(); html += `<p>${mdInline(line)}</p>`; }
  }
  closeList();
  return html;
}
function Markdown({ text }) { return <div className="markdown-body" dangerouslySetInnerHTML={{ __html: md(text) }} />; }

const HERMES_SUGGESTIONS = [
  "Where am I over-concentrated?",
  "What's my best risk/reward right now?",
  "Which holdings are below fair value?",
  "Summarise this week's research.",
  "Should I trim my biggest winner?",
];

/* ── Hermes chat hook — real API ──────────────────────────────────────────── */
function useHermes() {
  const [messages, setMessages] = useState([]); // {role, text, tools?, error?, pending?}
  const [busy, setBusy] = useState(false);

  const send = useCallback(async (text) => {
    if (!text || !text.trim() || busy) return;
    setBusy(true);
    let history = [];
    setMessages((prev) => {
      history = prev.filter((m) => !m.error && (m.role === "user" || m.role === "assistant"))
        .map((m) => ({ role: m.role, content: m.text }));
      return [...prev, { role: "user", text }, { role: "assistant", text: "", tools: [], pending: true }];
    });
    try {
      const apiMessages = [...history, { role: "user", content: text }];
      const r = await API.hermesChat(apiMessages);
      const tools = (r.tool_calls_made || []).map((c) => c.name);
      setMessages((m) => replaceLastAssistant(m, { role: "assistant", text: r.text || "", tools, model: r.model, pending: false }));
    } catch (e) {
      setMessages((m) => replaceLastAssistant(m, { role: "assistant", text: "", error: e.message || "Hermes is unavailable. Connect Codex in Settings.", pending: false }));
    } finally {
      setBusy(false);
    }
  }, [busy]);

  const reset = useCallback(() => setMessages([]), []);
  return { messages, send, busy, reset };
}
function replaceLastAssistant(list, replacement) {
  const out = list.slice();
  for (let i = out.length - 1; i >= 0; i--) {
    if (out[i].role === "assistant") { out[i] = replacement; break; }
  }
  return out;
}

function HermesThread({ messages, compact }) {
  const endRef = useRef(null);
  useEffect(() => { if (endRef.current) endRef.current.parentNode.scrollTop = endRef.current.offsetTop + 999; }, [messages]);
  return (
    <Col gap={compact ? 16 : 22} style={{ paddingBottom: 8 }}>
      {messages.map((m, i) => m.role === "user" ? (
        <Row key={i} justify="flex-end">
          <div style={{ background: "var(--sage-700)", color: "#fff", padding: "10px 14px", borderRadius: "16px 16px 4px 16px", maxWidth: "82%", fontSize: 14, lineHeight: 1.5, boxShadow: "var(--elev-1)" }}>{m.text}</div>
        </Row>
      ) : (
        <Row key={i} gap={10} align="flex-start">
          <div style={{ width: 28, height: 28, borderRadius: 9, background: "linear-gradient(140deg, var(--sage-500), var(--sage-800))", display: "grid", placeItems: "center", flexShrink: 0, marginTop: 2 }}>
            <Icon name="sparkles" size={14} style={{ color: "#fff" }} />
          </div>
          <div style={{ flex: 1, minWidth: 0 }}>
            {m.pending && (
              <Row gap={7} style={{ fontSize: 12, color: "var(--fg-2)" }}>
                <Icon name="loader" size={12} className="spin" style={{ color: "var(--fg-3)" }} />
                Reading your portfolio &amp; research…
              </Row>
            )}
            {!m.pending && m.tools && m.tools.length > 0 && (
              <Row gap={6} wrap style={{ marginBottom: 10 }}>
                {m.tools.map((t, ti) => (
                  <span key={ti} className="chip chip-tinted" style={{ fontSize: 11 }}>
                    <Icon name="check" size={11} style={{ color: "var(--sage-600)" }} /> {t}
                  </span>
                ))}
              </Row>
            )}
            {m.error ? (
              <Row gap={8} align="flex-start" style={{ background: "var(--danger-bg)", color: "var(--danger-fg)", padding: "10px 12px", borderRadius: "var(--radius-3)", fontSize: 13 }}>
                <Icon name="alert-circle" size={15} style={{ marginTop: 1, flexShrink: 0 }} /><span>{m.error}</span>
              </Row>
            ) : m.text ? (
              <div className="fade"><Markdown text={m.text} /></div>
            ) : null}
          </div>
        </Row>
      ))}
      <div ref={endRef} style={{ height: 1 }} />
    </Col>
  );
}

function HermesComposer({ onSend, busy, suggestions, showSuggestions }) {
  const [val, setVal] = useState("");
  const submit = () => { if (val.trim() && !busy) { onSend(val.trim()); setVal(""); } };
  return (
    <Col gap={10}>
      {showSuggestions && (
        <Row gap={7} wrap>
          {suggestions.map((s) => (
            <button key={s} className="chip" style={{ cursor: "pointer", padding: "5px 11px" }} onClick={() => !busy && onSend(s)}>{s}</button>
          ))}
        </Row>
      )}
      <Row gap={8} align="flex-end" style={{ background: "var(--bg-surface)", border: "1px solid var(--border-1)", borderRadius: "var(--radius-4)", padding: 8, boxShadow: "var(--elev-1)" }}>
        <textarea
          className="scroll-nice"
          value={val}
          onChange={(e) => setVal(e.target.value)}
          onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); submit(); } }}
          placeholder="Ask Hermes about your portfolio…"
          rows={1}
          style={{ flex: 1, border: 0, outline: 0, resize: "none", background: "transparent", color: "var(--fg-1)", fontSize: 14, lineHeight: 1.5, padding: "6px 8px", maxHeight: 120, fontFamily: "inherit" }}
        />
        <button className="btn btn-primary btn-icon" disabled={busy || !val.trim()} onClick={submit} aria-label="Send">
          <Icon name={busy ? "loader" : "arrow-up"} size={16} className={busy ? "spin" : ""} style={{ color: "#fff" }} />
        </button>
      </Row>
    </Col>
  );
}

/* ── Sidebar ──────────────────────────────────────────────────────────────── */
function Sidebar({ active, onNavigate, onLogout, user }) {
  const main = [
    { id: "today", label: "Heute", icon: "sun" },
    { id: "overview", label: "Overview", icon: "layout-dashboard" },
    { id: "portfolio", label: "Portfolio", icon: "wallet" },
    { id: "research", label: "Research", icon: "library" },
    { id: "recommendations", label: "Recommendations", icon: "git-fork" },
    { id: "hermes", label: "Hermes", icon: "sparkles" },
  ];
  const bottom = [
    { id: "settings", label: "Settings", icon: "settings" },
    { id: "system", label: "System status", icon: "activity" },
  ];
  const email = (user && user.email) || "";
  const initials = email ? email.slice(0, 2).toUpperCase() : "··";
  const name = email ? email.split("@")[0] : "Account";
  return (
    <aside className="scroll-nice" style={{ width: "var(--sidebar-w)", background: "var(--bg-surface)", borderRight: "1px solid var(--border-1)", padding: "18px 12px", display: "flex", flexDirection: "column", gap: 4, flexShrink: 0, height: "100%", overflowY: "auto" }}>
      <div style={{ padding: "2px 8px 16px", borderBottom: "1px solid var(--border-1)", marginBottom: 8 }}>
        <Logo withText size={30} />
      </div>
      {main.map((it) => <NavLink key={it.id} item={it} active={active === it.id} onClick={() => onNavigate(it.id)} />)}
      <div style={{ flex: 1 }} />
      <div style={{ borderTop: "1px solid var(--border-1)", paddingTop: 8, marginTop: 8, display: "flex", flexDirection: "column", gap: 4 }}>
        {bottom.map((it) => <NavLink key={it.id} item={it} active={active === it.id} onClick={() => onNavigate(it.id)} />)}
      </div>
      <button onClick={onLogout} style={{ marginTop: 6, padding: 10, background: "var(--bg-sunken)", border: "1px solid var(--border-1)", borderRadius: "var(--radius-3)", display: "flex", alignItems: "center", gap: 10, textAlign: "left", width: "100%" }}>
        <Avatar initials={initials} size="sm" gradient="linear-gradient(140deg, var(--sage-500), var(--sage-700))" />
        <div style={{ minWidth: 0, lineHeight: 1.2, flex: 1 }}>
          <div style={{ fontWeight: 600, fontSize: 13, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{name}</div>
          <div style={{ fontSize: 11, color: "var(--fg-3)" }}>Sign out</div>
        </div>
        <Icon name="log-out" size={14} style={{ color: "var(--fg-3)" }} />
      </button>
    </aside>
  );
}
function NavLink({ item, active, onClick }) {
  const [hover, setHover] = useState(false);
  return (
    <button onClick={onClick} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{ display: "flex", alignItems: "center", gap: 11, padding: "8px 10px", fontSize: 13.5, fontWeight: active ? 600 : 500,
        color: active ? "var(--signal-fg)" : "var(--fg-2)", background: active ? "var(--signal-bg)" : (hover ? "var(--bg-sunken)" : "transparent"),
        borderRadius: "var(--radius-3)", border: 0, width: "100%", textAlign: "left", letterSpacing: "-0.005em", transition: "background .12s, color .12s" }}>
      <Icon name={item.icon} size={16} style={{ color: active ? "var(--signal-accent)" : "var(--fg-3)" }} />
      <span style={{ flex: 1 }}>{item.label}</span>
    </button>
  );
}

/* ── Top bar ──────────────────────────────────────────────────────────────── */
function TopBar({ theme, onToggleTheme, onOpenHermes, summary, asOf, onRefresh, refreshing }) {
  const tv = summary ? summary.totalValue : null;
  const pct = summary ? summary.unrealizedPct : null;
  return (
    <header style={{ height: 60, flexShrink: 0, borderBottom: "1px solid var(--border-1)", background: "color-mix(in srgb, var(--bg-surface) 80%, transparent)", backdropFilter: "blur(8px)", display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0 24px", position: "sticky", top: 0, zIndex: 20 }}>
      <Row gap={14}>
        <Row gap={9} style={{ paddingRight: 16, borderRight: "1px solid var(--border-1)" }}>
          <span className="kpi-label" style={{ fontSize: 10 }}>Portfolio value</span>
          {tv != null
            ? <span className="mono" style={{ fontSize: 15, fontWeight: 600, letterSpacing: "-0.01em" }}>{fmt.eur(tv)}</span>
            : <Skel w={88} h={15} />}
          {pct != null && <Delta value={pct} kind="pct" size={12} />}
        </Row>
        <Row gap={6} style={{ fontSize: 12, color: "var(--fg-3)", whiteSpace: "nowrap" }}>
          <span className="dot dot-ok dot-pulse" />
          <span>{asOf ? "Updated " + fmt.time(asOf) : "Live"}</span>
        </Row>
      </Row>
      <Row gap={8}>
        <button className="btn btn-sm" onClick={onRefresh} disabled={refreshing}>
          <Icon name="refresh-cw" size={13} className={refreshing ? "spin" : ""} /> {refreshing ? "Refreshing…" : "Refresh"}
        </button>
        <button className="btn btn-sm" onClick={onOpenHermes}>
          <Icon name="sparkles" size={13} /> Ask Hermes
        </button>
        <button className="btn btn-icon btn-sm" onClick={onToggleTheme} aria-label="Toggle theme" title="Toggle theme">
          <Icon name={theme === "dark" ? "sun" : "moon"} size={15} />
        </button>
      </Row>
    </header>
  );
}

/* ── Hermes slide-out panel + launcher ────────────────────────────────────── */
function HermesPanel({ open, onClose }) {
  const hermes = useHermes();
  const fresh = hermes.messages.length === 0;
  return (
    <>
      <div onClick={onClose} style={{ position: "fixed", inset: 0, background: "rgba(20,23,26,0.32)", opacity: open ? 1 : 0, pointerEvents: open ? "auto" : "none", transition: "opacity .25s", zIndex: 60, backdropFilter: open ? "blur(2px)" : "none" }} />
      <aside style={{ position: "fixed", top: 0, right: 0, height: "100%", width: "min(440px, 92vw)", background: "var(--bg-app)", borderLeft: "1px solid var(--border-1)", boxShadow: "var(--elev-3)", zIndex: 61, transform: open ? "translateX(0)" : "translateX(102%)", transition: "transform .3s cubic-bezier(.2,.7,.2,1)", display: "flex", flexDirection: "column" }}>
        <Row justify="space-between" style={{ padding: "16px 18px", borderBottom: "1px solid var(--border-1)", flexShrink: 0 }}>
          <Row gap={10}>
            <div style={{ width: 30, height: 30, borderRadius: 9, background: "linear-gradient(140deg, var(--sage-500), var(--sage-800))", display: "grid", placeItems: "center" }}><Icon name="sparkles" size={15} style={{ color: "#fff" }} /></div>
            <div style={{ lineHeight: 1.15 }}>
              <div style={{ fontWeight: 600, fontSize: 15 }}>Hermes</div>
              <div style={{ fontSize: 11, color: "var(--fg-3)" }}>Your portfolio assistant</div>
            </div>
          </Row>
          <Row gap={4}>
            {hermes.messages.length > 0 && <button className="btn btn-icon btn-sm" onClick={hermes.reset} title="New chat"><Icon name="plus" size={15} /></button>}
            <button className="btn btn-icon btn-sm" onClick={onClose} aria-label="Close"><Icon name="x" size={15} /></button>
          </Row>
        </Row>
        <div className="scroll-nice" style={{ flex: 1, overflowY: "auto", padding: 18 }}>
          {fresh ? (
            <Col gap={14} style={{ paddingTop: 8 }}>
              <div style={{ width: 44, height: 44, borderRadius: 13, background: "linear-gradient(140deg, var(--sage-500), var(--sage-800))", display: "grid", placeItems: "center" }}><Icon name="sparkles" size={22} style={{ color: "#fff" }} /></div>
              <div>
                <div style={{ fontSize: 17, fontWeight: 600, letterSpacing: "-0.01em" }}>How can I help?</div>
                <p className="muted" style={{ fontSize: 13.5, margin: "4px 0 0", lineHeight: 1.55 }}>I read your live portfolio, your research library and Eulerpool valuations to give you buy / hold / sell reasoning.</p>
              </div>
            </Col>
          ) : <HermesThread messages={hermes.messages} compact />}
        </div>
        <div style={{ padding: 16, borderTop: "1px solid var(--border-1)", flexShrink: 0 }}>
          <HermesComposer onSend={hermes.send} busy={hermes.busy} suggestions={HERMES_SUGGESTIONS.slice(0, 3)} showSuggestions={fresh} />
        </div>
      </aside>
    </>
  );
}

function HermesLauncher({ onClick, hidden }) {
  if (hidden) return null;
  return (
    <button onClick={onClick} className="rise" style={{ position: "fixed", bottom: 26, right: 26, zIndex: 50, width: 54, height: 54, borderRadius: 999, border: 0, background: "linear-gradient(140deg, var(--sage-500), var(--sage-800))", boxShadow: "var(--elev-launcher)", display: "grid", placeItems: "center" }} title="Ask Hermes" aria-label="Ask Hermes">
      <Icon name="sparkles" size={22} style={{ color: "#fff" }} />
    </button>
  );
}

Object.assign(window, {
  Sidebar, TopBar, HermesPanel, HermesLauncher,
  useHermes, HermesThread, HermesComposer, Markdown, md, HERMES_SUGGESTIONS,
});
