// Gateway / Providers — connection status, capabilities, connection settings,
// provider catalog, and models. Wired to HERMES (gateway-status, connection-status,
// connection-settings, models) with an offline fallback to window.DATA so the
// standalone preview stays fully rendered. See DASH-GATEWAY-SPEC PART 2 + API-SPEC §7-8.
const { useState, useEffect, useCallback } = React;

// Static provider catalog from DASH-GATEWAY §2.5 (the wizard's PROVIDER_CATALOG).
// `auth` chips use the human labels from getAuthTypeLabel; `logo`/`c` mirror the
// look of the existing provider tiles in page-settings.jsx.
const PROVIDER_CATALOG = [
  { id: "anthropic", name: "Anthropic", desc: "Claude models — Haiku, Sonnet, and Opus.", auth: ["API Key", "CLI Token"], logo: "A\\", c: "#d97757" },
  { id: "openai", name: "OpenAI", desc: "GPT and reasoning models for chat and tools.", auth: ["API Key"], logo: "Oa", c: "#10a37f" },
  { id: "google", name: "Google", desc: "Gemini models with API key or OAuth.", auth: ["API Key", "OAuth"], logo: "Gm", c: "#4285f4" },
  { id: "openrouter", name: "OpenRouter", desc: "Unified access to many providers through one API.", auth: ["API Key"], logo: "OR", c: "#a78bfa" },
  { id: "minimax", name: "MiniMax", desc: "MiniMax foundation models and multimodal APIs.", auth: ["API Key"], logo: "M", c: "#f0883e" },
  { id: "ollama", name: "Ollama", desc: "Local models running on your machine via Ollama.", auth: ["Local"], logo: "Ol", c: "#cbd2dd" },
  { id: "atomic-chat", name: "Atomic Chat", desc: "Local LLMs via Atomic Chat — run Llama, Gemma, Qwen and more.", auth: ["Local"], logo: "AC", c: "#c6f24a" },
];

// Capability keys to surface (from gatewayStatus().capabilities), in display order.
const CAP_KEYS = [
  ["health", "Health"], ["chatCompletions", "Chat Completions"], ["models", "Models"],
  ["streaming", "Streaming"], ["sessions", "Sessions"], ["skills", "Skills"],
  ["memory", "Memory"], ["config", "Config"], ["jobs", "Jobs"], ["mcp", "MCP"],
  ["conductor", "Conductor"], ["dashboard", "Dashboard"],
];

// status -> { label, dot color }. enhanced is cyan-ish (no CSS class for it, so
// inline color); the rest reuse the status-dot palette.
const CONN_STATUS = {
  enhanced: { label: "Enhanced", color: "#22d3ee" },
  connected: { label: "Connected", color: "var(--success)" },
  partial: { label: "Partial", color: "var(--warn)" },
  disconnected: { label: "Disconnected", color: "var(--danger)" },
};

// Offline placeholder: every capability off.
const EMPTY_CAPS = CAP_KEYS.reduce((o, [k]) => { o[k] = false; return o; }, {});

function PageGateway({ toast }) {
  const [conn, setConn] = useState(null);        // connectionStatus()
  const [caps, setCaps] = useState(null);        // gatewayStatus().capabilities
  const [mode, setMode] = useState("");          // gatewayStatus().mode (chatMode-ish)
  const [models, setModels] = useState([]);      // listModels().models
  const [configured, setConfigured] = useState([]); // configuredProviders[]
  const [gw, setGw] = useState("");              // connectionSettings().gateway
  const [dash, setDash] = useState("");          // connectionSettings().dashboard
  const [live, setLive] = useState(null);        // null=loading, true=backend, false=offline
  const [saving, setSaving] = useState(false);
  const [selProv, setSelProv] = useState(null);

  const load = useCallback(async () => {
    let anyLive = false;
    // Gateway status / capabilities — the primary "is the backend there" signal.
    try {
      const gs = await HERMES.gatewayStatus();
      setCaps(gs?.capabilities || EMPTY_CAPS);
      setMode(gs?.mode || "");
      if (gs?.claudeUrl && !gw) setGw(gs.claudeUrl);
      if (gs?.dashboardUrl && !dash) setDash(gs.dashboardUrl);
      anyLive = true;
    } catch { setCaps(EMPTY_CAPS); }

    // Connection status (label + dot + active model + chatMode).
    try { setConn(await HERMES.connectionStatus()); anyLive = true; } catch { setConn(null); }

    // Editable gateway/dashboard URLs.
    try {
      const cs = await HERMES.connectionSettings();
      setGw(cs?.gateway || ""); setDash(cs?.dashboard || "");
      anyLive = true;
    } catch { /* keep whatever gateway-status gave us */ }

    // Models list (+ configured providers for tile status).
    try {
      const m = await HERMES.listModels();
      setModels(Array.isArray(m?.models) ? m.models : []);
      setConfigured(Array.isArray(m?.configuredProviders) ? m.configuredProviders : []);
      anyLive = true;
    } catch {
      setModels((window.DATA.models || []).map((id) => {
        const meta = modelMeta(id);
        return { id, provider: id.includes("/") ? id.split("/")[0] : (meta.prov || "hermes-agent").toLowerCase(), name: meta.short };
      }));
      setConfigured([]);
    }

    setLive(anyLive);
  }, [gw, dash]);

  useEffect(() => { load(); /* eslint-disable-next-line */ }, []);

  const reprobe = async () => {
    try {
      const r = await HERMES.gatewayReprobe();
      if (r?.capabilities) { setCaps(r.capabilities); setMode(r.mode || mode); }
      toast("Gateway re-probed — capabilities refreshed");
      load();
    } catch (e) { toast(e.message || "Re-probe failed"); }
  };

  const saveConnection = async () => {
    setSaving(true);
    try {
      await HERMES.setConnection({ gateway: gw, dashboard: dash });
      toast("Connection saved & reprobing capabilities…");
      await load();
    } catch (e) { toast(e.message || "Could not save connection"); }
    setSaving(false);
  };

  const status = conn?.status || (live ? "partial" : "disconnected");
  const meta = CONN_STATUS[status] || CONN_STATUS.disconnected;
  const activeModel = conn?.activeModel || conn?.modelInfo?.model || (models[0]?.id) || "—";
  const chatMode = conn?.chatMode || mode || "—";
  const capsView = caps || EMPTY_CAPS;
  const enabledCaps = CAP_KEYS.filter(([k]) => capsView[k]).length;

  // group models by provider for the Models card
  const grouped = {};
  for (const m of models) {
    const p = m.provider || (m.id && m.id.includes("/") ? m.id.split("/")[0] : "hermes-agent");
    (grouped[p] = grouped[p] || []).push(m);
  }
  const providerNames = Object.keys(grouped).sort();

  // configured-provider lookup for the provider tiles' status dots
  const isConfigured = (id) =>
    configured.includes(id) || providerNames.some((p) => p === id || p.includes(id));

  return (
    <div className="page">
      <PageHead eyebrow="Workspace" title="Gateway" sub="Providers, connection, and gateway capabilities for Hermes Agent.">
        {live === true && <span className="badge ok"><span className="d" />live</span>}
        {live === false && <span className="badge warn"><span className="d" />preview data</span>}
        {live === null && <span className="badge"><span className="d" />loading…</span>}
        <button className="btn btn-ghost" onClick={reprobe}><Icon name="refresh" size={16} />Re-probe</button>
      </PageHead>

      {/* ---- Connection status + capabilities ---- */}
      <div className="card" style={{ marginBottom: "var(--gap)" }}>
        <div className="card-head">
          <div>
            <h2>Connection status</h2>
            <p>Live link to the Hermes gateway — mode, active model, and detected capabilities.</p>
          </div>
        </div>

        <div className="grid cols-3" style={{ marginBottom: 18 }}>
          <div className="stat card" style={{ gap: 8 }}>
            <div className="stat-label mono" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: ".08em" }}>Status</div>
            <div className="flex" style={{ gap: 8, alignItems: "center" }}>
              <span className={cls("status-dot", live && "live")} style={{ background: meta.color }} />
              <span style={{ fontSize: 18, fontWeight: 650 }}>{meta.label}</span>
            </div>
            {conn?.detail && <div className="faint" style={{ fontSize: 12, lineHeight: 1.5 }}>{conn.detail}</div>}
          </div>
          <div className="stat card" style={{ gap: 8 }}>
            <div className="stat-label mono" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: ".08em" }}>Active model</div>
            <div className="mono" style={{ fontSize: 16, fontWeight: 650, wordBreak: "break-all" }}>{activeModel}</div>
          </div>
          <div className="stat card" style={{ gap: 8 }}>
            <div className="stat-label mono" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: ".08em" }}>Chat mode</div>
            <div className="mono" style={{ fontSize: 16, fontWeight: 650 }}>{chatMode}</div>
          </div>
        </div>

        <div className="flex between" style={{ marginBottom: 12 }}>
          <span className="section-title">Capabilities</span>
          <span className="faint mono" style={{ fontSize: 12 }}>{enabledCaps} / {CAP_KEYS.length} available</span>
        </div>
        <div className="cap-grid">
          {CAP_KEYS.map(([k, label]) => (
            <div key={k} className={cls("cap", capsView[k] ? "on" : "off")}>
              <span className="d" /><span>{label}</span>
            </div>
          ))}
        </div>
      </div>

      {/* ---- Connection settings ---- */}
      <div className="card" style={{ marginBottom: "var(--gap)" }}>
        <div className="card-head">
          <div>
            <h2>Connection settings</h2>
            <p>Point the workspace at your Hermes Agent services. Capabilities reprobe on save.</p>
          </div>
          <button className="btn btn-primary btn-sm" disabled={saving} onClick={saveConnection}>
            <Icon name="refresh" size={14} />{saving ? "Saving…" : "Save & reprobe"}
          </button>
        </div>
        <div className="grid cols-2">
          <div className="field">
            <label>Gateway URL</label>
            <input className="input mono" value={gw} onChange={(e) => setGw(e.target.value)} placeholder="http://127.0.0.1:8642" />
          </div>
          <div className="field">
            <label>Dashboard URL</label>
            <input className="input mono" value={dash} onChange={(e) => setDash(e.target.value)} placeholder="http://127.0.0.1:9119" />
          </div>
        </div>
        <div style={{ marginTop: 14, padding: "12px 14px", border: "1px solid var(--line)", borderRadius: 10, background: "var(--surface-2)", fontSize: 12.5, lineHeight: 1.6, color: "var(--muted)" }}>
          <b style={{ color: "var(--text)" }}>Tailscale / remote tip:</b> set the gateway to its Tailscale IP (e.g. <span className="mono">http://100.x.y.z:8642</span>) and make sure it listens on <span className="mono">0.0.0.0</span>. URLs must be valid http(s) — no restart needed, capabilities reprobe on save.
        </div>
      </div>

      {/* ---- Providers ---- */}
      <div className="card" style={{ marginBottom: "var(--gap)" }}>
        <div className="card-head">
          <div>
            <h2>Providers</h2>
            <p>API keys stay in your local Hermes config (<span className="mono">~/.hermes/config.yaml</span>) and are never sent to Studio.</p>
          </div>
          <button className="btn btn-ghost btn-sm" onClick={() => toast("Add Provider wizard — choose provider, auth, and add a key")}>
            <Icon name="plus" size={14} />Add Provider
          </button>
        </div>
        <div className="prov-grid">
          {PROVIDER_CATALOG.map((p) => {
            const on = isConfigured(p.id);
            return (
              <button
                key={p.id}
                className={cls("prov-tile", selProv === p.id && "on")}
                onClick={() => { setSelProv(p.id); toast(on ? `${p.name} · configured` : `${p.name} · open setup`); }}
                title={on ? "Configured provider" : "Not configured yet"}
              >
                <span className="pstat" style={{ background: on ? "var(--success)" : "var(--faint)" }} />
                <span className="badge-logo" style={{ background: `color-mix(in oklab, ${p.c} 20%, var(--surface-3))`, color: p.c }}>{p.logo}</span>
                <div>
                  <b>{p.name}</b>
                  <small>{p.desc}</small>
                </div>
                <div className="chips" style={{ marginTop: 2 }}>
                  {p.auth.map((a) => <span className="tag" key={a}>{a}</span>)}
                </div>
              </button>
            );
          })}
        </div>
      </div>

      {/* ---- Models ---- */}
      <div className="card">
        <div className="card-head">
          <div>
            <h2>Models</h2>
            <p>Models exposed by the gateway, grouped by provider. Active: <span className="mono" style={{ color: "var(--primary)" }}>{activeModel}</span></p>
          </div>
          <span className="faint mono" style={{ fontSize: 12 }}>{models.length} model{models.length === 1 ? "" : "s"}</span>
        </div>
        {!models.length ? (
          <div className="empty">No models reported by the gateway.</div>
        ) : (
          providerNames.map((prov) => (
            <div key={prov} style={{ marginBottom: 14 }}>
              <div className="flex between" style={{ marginBottom: 8 }}>
                <span className="section-title" style={{ textTransform: "capitalize" }}>{prov}</span>
                <span className="faint mono" style={{ fontSize: 11.5 }}>{grouped[prov].length}</span>
              </div>
              <div className="rows">
                {grouped[prov].map((m) => {
                  const isActive = m.id === activeModel;
                  return (
                    <div className="row" key={m.id} style={{ cursor: "default" }}>
                      <span className="glyph"><Icon name="cpu" size={15} /></span>
                      <div className="row-main">
                        <b className="mono" style={{ fontSize: 13 }}>{m.name || m.id}</b>
                        <div className="row-sub mono"><span>{m.id}</span></div>
                      </div>
                      {isActive && <span className="badge pri"><span className="d" />active</span>}
                    </div>
                  );
                })}
              </div>
            </div>
          ))
        )}
      </div>
    </div>
  );
}
window.PageGateway = PageGateway;
