// Memory + Skills + MCP
const { useState, useEffect } = React;

// live/preview badge — live===true -> ok "live", live===false -> warn "preview data"
function LiveBadge({ live }) {
  if (live === null) return null;
  return live
    ? <span className="badge ok"><span className="d" />live</span>
    : <span className="badge warn"><span className="d" />preview data</span>;
}

// ---- normalizers: map live API shapes back to the design data shape, guarding every field ----
function normMemory(res) {
  const arr = Array.isArray(res) ? res
    : Array.isArray(res?.items) ? res.items
    : Array.isArray(res?.memories) ? res.memories
    : Array.isArray(res?.results) ? res.results
    : Array.isArray(res?.files) ? res.files
    : Array.isArray(res?.entries) ? res.entries : [];
  return arr.map((m, i) => ({
    id: m?.id ?? m?.path ?? m?.key ?? ("m" + i),
    kind: (m?.kind ?? m?.type ?? "fact"),
    text: m?.text ?? m?.content ?? m?.summary ?? m?.snippet ?? m?.name ?? m?.path ?? "",
    scope: m?.scope ?? m?.project ?? m?.namespace ?? "global",
    updated: m?.updated ?? m?.updatedAt ?? m?.modified ?? m?.mtime ?? "—",
  }));
}

function normSkills(res) {
  const arr = Array.isArray(res) ? res
    : Array.isArray(res?.skills) ? res.skills
    : Array.isArray(res?.items) ? res.items : [];
  return arr.map((s, i) => ({
    id: s?.id ?? s?.name ?? s?.slug ?? ("s" + i),
    name: s?.name ?? s?.title ?? s?.id ?? "Skill",
    cat: s?.cat ?? s?.category ?? s?.kind ?? "Skill",
    uses: Number(s?.uses ?? s?.calls ?? s?.usage ?? 0) || 0,
    enabled: (s?.enabled ?? s?.active ?? s?.installed ?? false) === true,
    desc: s?.desc ?? s?.description ?? s?.summary ?? "",
  }));
}

function normMcp(res) {
  const arr = Array.isArray(res) ? res
    : Array.isArray(res?.servers) ? res.servers
    : Array.isArray(res?.mcpServers) ? res.mcpServers
    : Array.isArray(res?.items) ? res.items : [];
  return arr.map((s, i) => ({
    id: s?.id ?? s?.name ?? ("mcp" + i),
    name: s?.name ?? s?.id ?? "server",
    transport: s?.transport ?? s?.type ?? "stdio",
    status: s?.status ?? (s?.connected ? "connected" : "disabled"),
    tools: Number(s?.tools ?? s?.toolCount ?? (Array.isArray(s?.tools) ? s.tools.length : 0)) || 0,
    detail: s?.detail ?? s?.description ?? s?.url ?? s?.command ?? "",
  }));
}

function PageMemory({ toast }) {
  const [items, setItems] = useState(null);   // null = loading
  const [live, setLive] = useState(null);     // null=loading, true=backend, false=offline
  const [filter, setFilter] = useState("all");
  const [query, setQuery] = useState("");
  const kinds = ["all", "fact", "preference", "decision"];

  // initial load (list)
  useEffect(() => {
    let alive = true;
    HERMES.memoryList()
      .then((res) => { if (alive) { setItems(normMemory(res)); setLive(true); } })
      .catch(() => { if (alive) { setItems(normMemory(window.DATA.memory)); setLive(false); } });
    return () => { alive = false; };
  }, []);

  // server-side search when a query is present and we're live; otherwise filter locally
  useEffect(() => {
    if (live !== true) return;
    let alive = true;
    const term = query.trim();
    const fetcher = term ? HERMES.memorySearch(term) : HERMES.memoryList();
    fetcher
      .then((res) => { if (alive) setItems(normMemory(res)); })
      .catch(() => { /* keep current items on transient error */ });
    return () => { alive = false; };
  }, [query, live]);

  const base = items || [];
  const q = query.trim().toLowerCase();
  const shown = base.filter((m) =>
    (filter === "all" || m.kind === filter) &&
    // when offline (no server search), filter the text locally
    (live === true || !q || (m.text || "").toLowerCase().includes(q) || (m.scope || "").toLowerCase().includes(q))
  );

  return (
    <div className="page">
      <PageHead eyebrow="Knowledge" title="Memory" sub="Persistent facts, preferences, and decisions your agents recall across sessions.">
        <LiveBadge live={live} />
        <button className="btn btn-primary" onClick={() => toast("Add memory")}><Icon name="plus" size={16} />Add memory</button>
      </PageHead>
      <div className="flex between wrap" style={{ gap: 8, marginBottom: "var(--gap)" }}>
        <div className="flex" style={{ gap: 8 }}>
          {kinds.map((k) => <button key={k} className={cls("btn", "btn-sm", filter === k ? "btn-primary" : "btn-ghost")} style={{ textTransform: "capitalize" }} onClick={() => setFilter(k)}>{k}</button>)}
        </div>
        <div className="search" style={{ minWidth: 220, flex: "0 1 300px" }}>
          <Icon name="search" size={14} className="faint" />
          <input placeholder="Search memory…" value={query} onChange={(e) => setQuery(e.target.value)} />
        </div>
      </div>
      {items === null ? (
        <div className="empty muted">Loading memory…</div>
      ) : shown.length === 0 ? (
        <div className="empty muted">No memory entries{q ? " match your search." : "."}</div>
      ) : (
        <div className="grid cols-2">
          {shown.map((m) => (
            <div className="card" key={m.id} style={{ display: "flex", flexDirection: "column", gap: 11 }}>
              <div className="flex between">
                <span className={cls("kind-tag", "kind-" + m.kind)}>{m.kind}</span>
                <span className="tag">{m.scope}</span>
              </div>
              <p style={{ fontSize: 13.5, lineHeight: 1.55, margin: 0 }}>{m.text}</p>
              <div className="flex between faint" style={{ fontSize: 11.5 }}>
                <span className="mono">updated {m.updated}</span>
                <button className="btn btn-subtle btn-sm" onClick={() => toast("Edited")}><Icon name="edit" size={13} /></button>
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}
window.PageMemory = PageMemory;

function PageSkills({ toast }) {
  const [skills, setSkills] = useState(null);   // null = loading
  const [live, setLive] = useState(null);       // null=loading, true=backend, false=offline

  useEffect(() => {
    let alive = true;
    HERMES.listSkills()
      .then((res) => { if (alive) { setSkills(normSkills(res)); setLive(true); } })
      .catch(() => { if (alive) { setSkills(normSkills(window.DATA.skills)); setLive(false); } });
    return () => { alive = false; };
  }, []);

  const toggle = async (sk) => {
    const next = !sk.enabled;
    // optimistic update
    setSkills((s) => (s || []).map((k) => k.id === sk.id ? { ...k, enabled: next } : k));
    if (live !== true) { toast(`${sk.name} ${next ? "enabled" : "disabled"}`); return; }
    try {
      await HERMES.toggleSkill({ id: sk.id, name: sk.name, enabled: next });
      toast(`${sk.name} ${next ? "enabled" : "disabled"}`);
    } catch (err) {
      // revert on failure
      setSkills((s) => (s || []).map((k) => k.id === sk.id ? { ...k, enabled: sk.enabled } : k));
      toast(err?.message || "Toggle failed");
    }
  };

  const list = skills || [];
  const on = list.filter((s) => s.enabled).length;
  return (
    <div className="page">
      <PageHead eyebrow="Knowledge" title="Skills" sub="Capabilities your agents can call. Toggle to enable across the workspace.">
        <LiveBadge live={live} />
        <span className="badge ok"><span className="d" />{on} enabled</span>
        <button className="btn btn-primary" onClick={() => toast("Install skill")}><Icon name="plus" size={16} />Install</button>
      </PageHead>
      {skills === null ? (
        <div className="empty muted">Loading skills…</div>
      ) : list.length === 0 ? (
        <div className="empty muted">No skills installed.</div>
      ) : (
        <div className="grid cols-3">
          {list.map((s) => (
            <div className="card skill-card" key={s.id} style={{ opacity: s.enabled ? 1 : 0.62 }}>
              <div className="flex between">
                <div className="stat-icon" style={{ background: "var(--primary-soft)", color: "var(--primary)" }}><Icon name="skills" size={17} /></div>
                <Toggle on={s.enabled} onChange={() => toggle(s)} />
              </div>
              <div><div style={{ fontWeight: 650, fontSize: 14.5 }}>{s.name}</div><div className="faint mono" style={{ fontSize: 11 }}>{s.cat} · {fmt(s.uses)} calls</div></div>
              <p className="muted" style={{ fontSize: 12.5, margin: 0, lineHeight: 1.5 }}>{s.desc}</p>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}
window.PageSkills = PageSkills;

function PageMCP({ toast }) {
  const [servers, setServers] = useState(null);   // null = loading
  const [live, setLive] = useState(null);         // null=loading, true=backend, false=offline

  useEffect(() => {
    let alive = true;
    HERMES.listMcp()
      .then((res) => { if (alive) { setServers(normMcp(res)); setLive(true); } })
      .catch(() => { if (alive) { setServers(normMcp(window.DATA.mcpServers)); setLive(false); } });
    return () => { alive = false; };
  }, []);

  const tone = { connected: "ok", "needs-auth": "bad", disabled: "" };
  const list = servers || [];
  const totalTools = list.filter((s) => s.status === "connected").reduce((a, b) => a + (b.tools || 0), 0);
  return (
    <div className="page">
      <PageHead eyebrow="Knowledge" title="MCP Servers" sub="Model Context Protocol servers — external tools and data your agents connect to.">
        <LiveBadge live={live} />
        <span className="badge pri">{totalTools} tools live</span>
        <button className="btn btn-primary" onClick={() => toast("Add MCP server")}><Icon name="plus" size={16} />Add server</button>
      </PageHead>
      <div className="card">
        {servers === null ? (
          <div className="empty muted">Loading MCP servers…</div>
        ) : list.length === 0 ? (
          <div className="empty muted">No MCP servers configured.</div>
        ) : (
          <table className="tbl">
            <thead><tr><th>Server</th><th>Transport</th><th>Tools</th><th>Detail</th><th>Status</th><th></th></tr></thead>
            <tbody>
              {list.map((s) => (
                <tr key={s.id} className="clk" onClick={() => toast(s.name)}>
                  <td><div className="flex" style={{ gap: 9 }}><div className="glyph" style={{ width: 30, height: 30, fontSize: 12 }}><Icon name="mcp" size={15} /></div><span className="mono" style={{ fontWeight: 600 }}>{s.name}</span></div></td>
                  <td><span className="tag">{s.transport}</span></td>
                  <td className="mono faint">{s.tools}</td>
                  <td className="faint" style={{ fontSize: 12.5 }}>{s.detail}</td>
                  <td><span className={cls("badge", tone[s.status])}><StatusDot status={s.status === "connected" ? "connected" : s.status === "needs-auth" ? "needs-login" : "idle"} live={s.status === "connected"} />{s.status}</span></td>
                  <td style={{ textAlign: "right" }}>{s.status === "needs-auth" ? <button className="btn btn-primary btn-sm" onClick={(e) => { e.stopPropagation(); toast("Re-auth " + s.name); }}>Re-auth</button> : <button className="btn btn-subtle btn-sm" onClick={(e) => { e.stopPropagation(); toast("Config"); }}><Icon name="sliders" size={13} /></button>}</td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>
    </div>
  );
}
window.PageMCP = PageMCP;
