/**
 * zeq-page-api.js — defines window.zeq in the PAGE's main world (KP.1).
 *
 * Injected (world: MAIN) on sites the user grants. Gives the page's own
 * JavaScript a small, safe handle on the ZeqVM physics engine:
 *
 *   await window.zeq.compute(["KO42"], { mass: 1, acceleration: 9.8 })
 *   await window.zeq.solve({ prompt, mass, ... })
 *   await window.zeq.multibody({ bodies: [...] })
 *   await window.zeq.verify(proof, claim)
 *   await window.zeq.pulse()           // live 1.287 Hz snapshot
 *   await window.zeq.operators({ search: "quantum" })
 *   window.zeq.modulate(value)         // KO42 modulation (local, sync-ish)
 *
 * Calls are window.postMessage'd to the isolated relay (zeq-page-bridge.js),
 * which forwards to the service worker (holds the token, no CORS) and posts the
 * sanitized result back. The page NEVER sees the token or API key.
 *
 * @version 1.287.13
 * @license CC BY 4.0 — Zeq. H / Zeq 1.287 Hz Limited
 */
(() => {
  "use strict";
  if (window.zeq && window.zeq.__zeqvm) return; // idempotent

  const PENDING = new Map();
  let seq = 0;

  function call(method, args) {
    return new Promise((resolve, reject) => {
      const id = "zeq_" + (++seq) + "_" + Date.now();
      PENDING.set(id, { resolve, reject });
      window.postMessage({ __zeq_req: true, id, method, args: args || {} }, window.location.origin);
      setTimeout(() => {
        if (PENDING.has(id)) { PENDING.delete(id); reject(new Error("zeq: request timed out")); }
      }, 45000);
    });
  }

  window.addEventListener("message", (e) => {
    if (e.source !== window) return;
    const d = e.data;
    if (!d || d.__zeq_res !== true || !PENDING.has(d.id)) return;
    const { resolve, reject } = PENDING.get(d.id);
    PENDING.delete(d.id);
    if (d.ok) resolve(d.data);
    else {
      const err = new Error(d.error || (d.data && d.data.error && (d.data.error.message || d.data.error)) || "zeq: engine error");
      err.status = d.status; err.data = d.data;
      reject(err);
    }
  });

  const api = {
    __zeqvm: "1.287",
    // Operator compute → { value, unit, equation, zeqProof, R_t, phase, … }.
    // On a dimensional mismatch the engine throws with .status=400 and the
    // 7-step protocol trace in .data — that's the physical compiler, not a bug.
    compute: (operators, inputs) => call("compute", { operators: Array.isArray(operators) ? operators : (operators ? [operators] : ["KO42"]), inputs: inputs || {} }),
    // Master-equation ODE solver (single body).
    solve: (spec) => call("solve", spec || {}),
    // N-body coupled ODE.
    multibody: (spec) => call("multibody", spec || {}),
    // Multi-node lattice compute.
    lattice: (spec) => call("lattice", spec || {}),
    // KO42 metric shift / re-alignment.
    shift: (spec) => call("shift", spec || {}),
    // Public proof (no key needed server-side).
    prove: (spec) => call("prove", spec || {}),
    // Verify a ZeqProof. verify(proofObj) or verify(proofHex, {operatorIds,R_t,zeqond}).
    verify: (proof, claim) => call("verify", (proof && typeof proof === "object") ? proof : Object.assign({ proof }, claim || {})),
    // Live HulyaPulse snapshot { pulseHz, zeqond, phase, R_t, … }.
    pulse: () => call("pulse", {}),
    // Operator registry (1,500+ catalogued). operators({ search, domain, limit }).
    operators: (q) => call("operators", q || {}),
    // KO42 modulation R(t)=S·[1+α·sin(2π·1.287·t)] — computed locally, no network.
    modulate: (value) => call("modulate", { value }),
  };

  try {
    Object.defineProperty(window, "zeq", { value: Object.freeze(api), configurable: true, enumerable: true, writable: false });
  } catch (_) { window.zeq = api; }
  // Let page code know the engine is ready (so it can await injection).
  try { window.dispatchEvent(new CustomEvent("zeq:ready", { detail: { version: "1.287", methods: Object.keys(api).filter((k) => k !== "__zeqvm") } })); } catch (_) {}
})();
