/**
 * MachineTab — spin up & control your ZeqVM state machine from the side panel.
 *
 * K2: when a user signs in, their personal state machine (auto-provisioned at
 * register, or minted here) stops being an isolated thing on the website — it
 * surfaces right in the browser. From here they can:
 *   • spin up a machine (POST /api/chain/state-machines — first one free)
 *   • see its entangled-state / observer (recent hash-linked activity)
 *   • open its app surface (/s/<slug>/) and observer (/state/?slug=)
 *   • open any of its built pages (/s/<slug>/p/<page>/)
 *
 * Depends on: window.ZeqConfig, window.ZeqAuth.
 *
 * @version 1.287.6
 * @license CC BY 4.0 — Zeq. H / Zeq 1.287 Hz Limited
 */
const MachineTab = (() => {
  "use strict";

  let _containerId = null;
  let _machine = null;
  let _busy = false;

  function esc(s) { return String(s == null ? "" : s).replace(/[&<>"]/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" }[c])); }

  // Apps open on the active ZeqVM origin; ecosystem domains open live.
  const APPS = [
    { label: "App Store", path: "/apps/" },
    { label: "ZeqPM", path: "/apps/zeqpm/" },
    { label: "Vault", path: "/vault/" },
    { label: "SDK", path: "/sdk/" },
    { label: "Observer", path: "/state/" },
  ];
  const ECOSYSTEM = [
    { label: "zeq.dev", url: "https://zeq.dev" },
    { label: "zeqond", url: "https://zeqond.com" },
    { label: "hulyapulse", url: "https://hulyapulse.com" },
    { label: "1287hz", url: "https://1287hz.com" },
    { label: "hulyasmath", url: "https://hulyasmath.com" },
    { label: "hulyas.org", url: "https://hulyas.org" },
    { label: "zeqstate", url: "https://zeqstate.com" },
    { label: "zeqsdk", url: "https://zeqsdk.com" },
    { label: "zeqapi", url: "https://zeqapi.com" },
    { label: "zeq.me", url: "https://zeq.me" },
  ];

  // Live app list from the App Store registry (/api/store/apps). Falls back to
  // a minimal static set if the registry is unreachable.
  async function _fetchApps() {
    try {
      const api = await _api();
      const r = await fetch(api + "/store/apps", { headers: _headers() });
      if (!r.ok) return null;
      const j = await r.json().catch(() => ({}));
      const arr = j.apps || (Array.isArray(j) ? j : []);
      return Array.isArray(arr) && arr.length ? arr : null;
    } catch (_) { return null; }
  }

  function _renderLauncher(origin, liveApps) {
    const list = (liveApps && liveApps.length)
      ? liveApps.map((a) => ({ label: ((a.icon ? a.icon + " " : "") + (a.name || a.slug)), path: a.path || ("/apps/" + a.slug + "/"), beta: a.status && a.status !== "live" }))
      : APPS.map((a) => ({ label: a.label, path: a.path, beta: false }));
    const apps = list.map((a) =>
      '<button class="btn" data-launch="' + esc(origin + a.path) + '" style="font-size:11px;padding:7px 6px;text-align:left">' + esc(a.label) + (a.beta ? ' <span style="color:var(--text-muted);font-size:9px">beta</span>' : "") + "</button>"
    ).join("");
    const eco = ECOSYSTEM.map((d) =>
      '<button class="btn" data-launch="' + esc(d.url) + '" style="font-size:10px;padding:6px 6px;color:var(--text-secondary)">' + esc(d.label) + "</button>"
    ).join("");
    return (
      '<div class="settings-section"><h4>Apps</h4>' +
      '<div style="display:grid;grid-template-columns:repeat(2,1fr);gap:6px">' + apps + "</div></div>" +
      '<div class="settings-section"><h4>Ecosystem</h4>' +
      '<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:6px">' + eco + "</div>" +
      '<p style="font-size:10px;color:var(--text-muted);margin-top:8px">One ZeqVM, ten doors. Use ours, or fork your own.</p></div>'
    );
  }

  async function _origin() { return await ZeqConfig.origin(); }
  async function _api() { return await ZeqConfig.api(); }
  function _authed() { return typeof ZeqAuth !== "undefined" && ZeqAuth.isAuthenticated(); }
  function _headers() {
    const h = { "Content-Type": "application/json" };
    if (_authed()) Object.assign(h, ZeqAuth.getHeaders());
    return h;
  }
  function _slugForZid(zid) { return String(zid || "").toLowerCase(); }

  // Apps open INSIDE the extension panel (not a new browser tab). Falls back
  // to a tab only if the in-panel viewer isn't available.
  function _openTab(url, title) {
    if (typeof window !== "undefined" && typeof window.openAppInPanel === "function") { window.openAppInPanel(url, title || "App"); return; }
    try { chrome.tabs.create({ url }); } catch (_) { window.open(url, "_blank"); }
  }

  // ── Data ───────────────────────────────────────────────────────────────
  async function _resolveMine() {
    const user = ZeqAuth.getUser();
    if (!user?.zid) return null;
    const api = await _api();
    const slug = _slugForZid(user.zid);
    try {
      const r = await fetch(api + "/chain/state-machines/" + encodeURIComponent(slug), { headers: _headers() });
      if (r.status === 404) return null;
      const j = await r.json().catch(() => ({}));
      if (r.ok && j.ok && j.machine) return j.machine;
      return null;
    } catch (_) { return null; }
  }

  async function _spinUp() {
    const user = ZeqAuth.getUser();
    const api = await _api();
    const displayName = (user?.name && user.name !== user.zid) ? (user.name + "'s machine") : "My ZeqVM machine";
    const r = await fetch(api + "/chain/state-machines", {
      method: "POST", headers: _headers(),
      body: JSON.stringify({ display_name: displayName }),
    });
    const j = await r.json().catch(() => ({}));
    if (r.ok && j.machine) {
      // Stash the one-time API key locally so app-control/compute works later (K4).
      if (j.rawApiKey || j.raw_api_key) {
        try { await chrome.storage.local.set({ ["zeq_sm_key_" + j.machine.slug]: (j.rawApiKey || j.raw_api_key) }); } catch (_) {}
      }
      return { slug: j.machine.slug, created: true };
    }
    if (r.status === 409 && (j.existing_slug || j.machine?.slug)) {
      return { slug: j.existing_slug || j.machine.slug, created: false };
    }
    if (r.status === 402) throw new Error("Spinning up costs ZEQ — top up in your Vault. (Your first machine is free; you may already have one.)");
    throw new Error(j.error_description || j.error || ("Spin-up failed (" + r.status + ")"));
  }

  async function _recentActivity(slug) {
    const api = await _api();
    try {
      const r = await fetch(api + "/chain/" + encodeURIComponent(slug) + "/explore", { headers: _headers() });
      if (!r.ok) return [];
      const j = await r.json().catch(() => ({}));
      const arr = j.rows || j.events || j.blocks || j.transitions || j.recent || (Array.isArray(j) ? j : []);
      return Array.isArray(arr) ? arr.slice(0, 6) : [];
    } catch (_) { return []; }
  }

  async function _pages(slug) {
    const api = await _api();
    try {
      const r = await fetch(api + "/state-machines/" + encodeURIComponent(slug) + "/pages", { headers: _headers() });
      if (!r.ok) return [];
      const j = await r.json().catch(() => ({}));
      const arr = j.pages || j.data || (Array.isArray(j) ? j : []);
      return Array.isArray(arr) ? arr : [];
    } catch (_) { return []; }
  }

  // ── K5 — encryption/SSL posture (real, live) ─────────────────────────────
  async function _security(slug) {
    const api = await _api();
    const out = { mlkem: null, ssl: null };
    try {
      const r = await fetch(api + "/keyex/" + encodeURIComponent(slug) + "/pubkey", { headers: _headers() });
      if (r.ok) { const j = await r.json(); out.mlkem = { alg: j.alg, fp: j.fingerprint, version: j.version }; }
    } catch (_) {}
    try {
      const r = await fetch(api + "/ssl/credentials?machine=" + encodeURIComponent(slug), { headers: _headers() });
      if (r.ok) { const j = await r.json(); out.ssl = { count: (j.credentials || []).length, zeqond: j.current_zeqond }; }
    } catch (_) {}
    return out;
  }
  function _renderSecurity(sec) {
    if (!sec) return "";
    const km = sec.mlkem;
    const ssl = sec.ssl;
    return '<div class="settings-section"><h4>Security — entangled into the browser</h4><div class="status-card">' +
      '<div class="status-row"><span class="status-label">Post-quantum key</span><span class="status-value">' +
        (km ? esc(km.alg || "ML-KEM-768") + " ✓" : "—") + "</span></div>" +
      (km && km.fp ? '<div class="status-row"><span class="status-label">PQ fingerprint</span><span class="status-value" style="font-family:monospace;font-size:10px">' + esc(String(km.fp).slice(0, 20)) + "…</span></div>" : "") +
      '<div class="status-row"><span class="status-label">ZeqSSL credentials</span><span class="status-value">' +
        (ssl ? (ssl.count > 0 ? ssl.count + " active ✓" : "none issued") : "—") + "</span></div>" +
      ((ssl && ssl.count === 0) ? '<button class="btn" id="mt-ssl-issue" style="width:100%;margin-top:6px;font-size:11px">Issue ZeqSSL credential</button>' : "") +
      '<div class="status-row"><span class="status-label">TESC auth window</span><span class="status-value">phase-locked · 0.777&nbsp;s</span></div>' +
      '<div id="mt-ssl-msg" style="font-size:10.5px;color:var(--accent-mint);margin-top:4px;display:none"></div>' +
      '<p style="font-size:10px;color:var(--text-muted);margin:6px 0 0">Your machine carries a live ML-KEM-768 post-quantum key (' + (km ? "ready" : "unavailable") + '). ZeqSSL credentials + TESC phase-locked tags secure cross-domain and messaging traffic.</p>' +
      "</div></div>";
  }

  // ── Render ───────────────────────────────────────────────────────────────
  function _wrap(inner) { return '<div class="tab-scroll" style="padding:12px">' + inner + "</div>"; }

  function _renderSignedOut() {
    return _wrap(
      '<div class="settings-section"><h4>Your ZeqVM machine</h4>' +
      '<div class="status-card"><p style="font-size:12px;color:var(--text-secondary);line-height:1.5;margin:0">' +
      "Sign in (header badge, top-right) to spin up and control your state machine directly from the browser — entangled to the live ZeqVM." +
      "</p></div></div>"
    );
  }

  function _renderNoMachine() {
    return (
      '<div class="settings-section"><h4>Your ZeqVM machine</h4>' +
      '<div class="status-card">' +
      '<p style="font-size:12px;color:var(--text-secondary);line-height:1.5;margin:0 0 10px">' +
      "You don't have a state machine yet. Spin one up — your first is free — and it becomes your sovereign, hash-linked machine on the live ZeqVM." +
      "</p>" +
      '<button class="btn btn-primary" id="mt-spinup" style="width:100%">Spin up my machine</button>' +
      '<div class="err" id="mt-err" style="color:#ef4444;font-size:11px;margin-top:8px;display:none"></div>' +
      "</div></div>"
    );
  }

  function _activityRow(ev) {
    const type = esc(ev.type || ev.event_type || ev.kind || "event");
    const hash = esc(String(ev.hash || ev.payload_hash || ev.id || "").slice(0, 10));
    const z = ev.zeqond || ev.z || ev.created_zeqond;
    const when = z != null ? ("Zeqond " + esc(String(z))) : (ev.created_at ? esc(String(ev.created_at).slice(0, 19)) : "");
    return '<div class="status-row"><span class="status-label">' + type + (hash ? ' <span style="color:var(--text-muted);font-family:monospace">' + hash + "…</span>" : "") +
      '</span><span class="status-value" style="font-size:10px">' + when + "</span></div>";
  }

  function _renderMachine(m, activity, pages) {
    const slug = esc(m.slug);
    const name = esc(m.displayName || m.display_name || m.slug);
    const isPublic = (m.isPublic ?? m.is_public) ? "Public" : "Private";
    let html =
      '<div class="settings-section"><h4>Your ZeqVM machine</h4>' +
      '<div class="status-card">' +
      '<div class="status-row"><span class="status-label">Machine</span><span class="status-value" style="color:var(--accent-cyan)">' + name + "</span></div>" +
      '<div class="status-row"><span class="status-label">Slug</span><span class="status-value" style="font-family:monospace;font-size:11px">' + slug + "</span></div>" +
      '<div class="status-row"><span class="status-label">Visibility</span><span class="status-value">' + isPublic + "</span></div>" +
      '<div style="display:flex;gap:6px;margin-top:10px;flex-wrap:wrap">' +
      '<button class="btn btn-primary" data-open="app" style="flex:1;min-width:110px" title="Build apps in-panel — chat names your repo, files & contracts auto-save with a ZeqProof">⚛ Workbench</button>' +
      '<button class="btn" data-open="zeqgit" style="flex:1;min-width:90px" title="Your git + PDF repository — every project a repo, every commit a ZeqProof">ZeqGit</button>' +
      '<button class="btn" data-open="observer" style="flex:1;min-width:90px">Observer ↗</button>' +
      '<button class="btn" id="mt-refresh" title="Refresh" style="padding:6px 10px">↻</button>' +
      "</div></div></div>";

    // Entangled-state / observer activity
    html += '<div class="settings-section"><h4>Entangled state — recent</h4><div class="status-card">';
    if (activity.length) html += activity.map(_activityRow).join("");
    else html += '<p style="font-size:11px;color:var(--text-muted);margin:0">No recent activity yet. Open the app and make a transition.</p>';
    html += "</div></div>";

    // Apps / pages built on this machine
    html += '<div class="settings-section"><h4>Apps on this machine</h4><div class="status-card" id="mt-pages">';
    if (pages.length) {
      html += pages.map((p) => {
        const ps = esc(p.slug || p.page_slug || p.id || "main");
        const pn = esc(p.title || p.name || ps);
        return '<div class="status-row"><span class="status-label">' + pn + '</span>' +
          '<button class="btn" data-page="' + ps + '" style="font-size:10px;padding:3px 8px">Open ↗</button></div>';
      }).join("");
    } else {
      html += '<p style="font-size:11px;color:var(--text-muted);margin:0">No pages yet. Open the app to build one.</p>';
    }
    html += "</div></div>";

    return html;
  }

  function _bind(container) {
    container.querySelector("#mt-spinup")?.addEventListener("click", async (e) => {
      if (_busy) return; _busy = true;
      const btn = e.currentTarget; const err = container.querySelector("#mt-err");
      btn.disabled = true; btn.textContent = "Spinning up…"; if (err) err.style.display = "none";
      try {
        const r = await _spinUp();
        await render(); // re-resolve and show the machine
      } catch (ex) {
        if (err) { err.textContent = ex.message; err.style.display = "block"; }
        btn.disabled = false; btn.textContent = "Spin up my machine";
      } finally { _busy = false; }
    });

    container.querySelectorAll("[data-open]").forEach((b) => b.addEventListener("click", async () => {
      const origin = await _origin();
      const slug = _machine?.slug;
      if (!slug) return;
      const what = b.getAttribute("data-open");
      // Host the live web surfaces IN-PANEL so the extension inherits the full
      // Workbench — chat, the name-your-app/repo popup, per-chat unique repos,
      // file/page/contract auto-save and ZeqProof links — with zero drift (it
      // IS the web surface; the auth-bridge supplies the iframe its token).
      const inPanel = (typeof window !== "undefined" && typeof window.openAppInPanel === "function");
      if (what === "app") {
        const url = origin + "/s/" + slug + "/?embed=1";
        inPanel ? window.openAppInPanel(url, "Workbench") : _openTab(origin + "/s/" + slug + "/", "Workbench");
      } else if (what === "zeqgit") {
        const url = origin + "/zeqgit/?embed=1";
        inPanel ? window.openAppInPanel(url, "ZeqGit") : _openTab(origin + "/zeqgit/", "ZeqGit");
      } else {
        const url = origin + "/apps/observer/?slug=" + encodeURIComponent(slug);
        inPanel ? window.openAppInPanel(url, "Observer") : _openTab(url, "Observer");
      }
    }));

    container.querySelector("#mt-refresh")?.addEventListener("click", () => render());

    container.querySelector("#mt-ssl-issue")?.addEventListener("click", async (e) => {
      const btn = e.currentTarget; const msg = container.querySelector("#mt-ssl-msg");
      if (!_machine) return;
      btn.disabled = true; btn.textContent = "Issuing…";
      try {
        const api = await _api();
        const r = await fetch(api + "/ssl/credentials/issue", { method: "POST", headers: _headers(), body: JSON.stringify({ machine: _machine.slug, mode: "A" }) });
        const j = await r.json().catch(() => ({}));
        if (!r.ok) throw new Error(j.error_description || j.error || ("issue failed (" + r.status + ")"));
        if (msg) { msg.textContent = "ZeqSSL credential issued ✓ kid " + String(j.kid || j.credential?.kid || "").slice(0, 12); msg.style.display = "block"; }
        setTimeout(() => render(), 900);
      } catch (ex) { if (msg) { msg.textContent = ex.message; msg.style.color = "var(--accent-red)"; msg.style.display = "block"; } btn.disabled = false; btn.textContent = "Issue ZeqSSL credential"; }
    });

    container.querySelectorAll("[data-launch]").forEach((b) => b.addEventListener("click", () => _openTab(b.getAttribute("data-launch"), (b.textContent || "App").replace(/[↗\s]+$/, ""))));

    container.querySelectorAll("[data-page]").forEach((b) => b.addEventListener("click", async () => {
      const origin = await _origin();
      const slug = _machine?.slug;
      if (!slug) return;
      _openTab(origin + "/s/" + slug + "/p/" + b.getAttribute("data-page") + "/", "App page");
    }));
  }

  // ── Public ───────────────────────────────────────────────────────────────
  async function render() {
    const container = document.getElementById(_containerId);
    if (!container) return;
    if (!_authed()) { container.innerHTML = _renderSignedOut(); return; }

    container.innerHTML = _wrap('<div class="settings-section"><div class="status-card"><p style="font-size:12px;color:var(--text-muted);margin:0">Resolving your machine…</p></div></div>');

    const origin = await _origin();
    const liveApps = await _fetchApps();
    _machine = await _resolveMine();
    if (!_machine) { container.innerHTML = _wrap(_renderNoMachine() + _renderLauncher(origin, liveApps)); _bind(container); return; }

    const [activity, pages, sec] = await Promise.all([_recentActivity(_machine.slug), _pages(_machine.slug), _security(_machine.slug)]);
    container.innerHTML = _wrap(_renderMachine(_machine, activity, pages) + _renderSecurity(sec) + _renderLauncher(origin, liveApps));
    _bind(container);
  }

  function init(containerId) {
    _containerId = containerId;
    render();
  }

  return { init, render };
})();

if (typeof module !== "undefined" && module.exports) { module.exports = MachineTab; }
