/**
 * zeq-project-repo.js — shared per-project / per-chat ZeqGit repo logic.
 *
 * ONE source of truth, consumed by every surface so they can never drift:
 *   • Web Workbench  (apps/zeq-dev/public/pulse/workbench/files-panel.js)
 *   • Chrome ext     (zeq-apps/zeq-mi-chrome)
 *   • VS Code ext    (zeq-apps/zeq-vs-code-sdk)
 *
 * Every project (a Pulse chat, a CLI contract, or a VS Code workspace folder)
 * gets a UNIQUE repo: slug(name) + "-" + a stable id (content hash or UUID).
 * Renames keep the repo (the id never changes). Files/pages/contracts mirror to
 * the repo through the framework's /zeqgit-bridge, each commit ZeqProof-anchored.
 *
 * Host-agnostic: callers pass a transport { origin, token, fetch }.
 *   - origin : framework origin, e.g. "https://www.zeq.dev" ("" = same-origin)
 *   - token  : the v3 session Bearer token (one ZID → one ZeqGit account)
 *   - fetch  : optional fetch impl (Node hosts pass their own)
 *
 * @version 1.0.0  @license CC BY 4.0 — Zeq 1.287 Hz Limited
 */
(function (root, factory) {
  var mod = factory();
  if (typeof module !== "undefined" && module.exports) module.exports = mod;
  if (typeof window !== "undefined") window.ZeqProjectRepo = mod;
  else if (typeof self !== "undefined") self.ZeqProjectRepo = mod;
})(typeof self !== "undefined" ? self : this, function () {
  "use strict";

  function slugify(t) {
    return String(t || "").toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
  }
  // FNV-1a 32-bit → 8 hex. Deterministic, dependency-free, identical everywhere.
  function fnv(s) {
    var h = 2166136261 >>> 0;
    for (var i = 0; i < s.length; i++) { h ^= s.charCodeAt(i); h = Math.imul(h, 16777619) >>> 0; }
    return ("00000000" + h.toString(16)).slice(-8);
  }
  // Stable 16-hex id derived from CONTENT (e.g. a chat's first message). Same
  // content → same id → same repo across reloads/devices; survives renames.
  function chatId(fp) { return fnv(fp) + fnv(fp.length + "|" + fp.split("").reverse().join("")); }
  // Random 32-hex id (for popup-named projects / workspaces with no content key).
  function uuid() {
    try { if (typeof crypto !== "undefined" && crypto.randomUUID) return crypto.randomUUID().replace(/-/g, ""); } catch (e) {}
    var s = ""; for (var i = 0; i < 32; i++) s += Math.floor(Math.random() * 16).toString(16); return s;
  }
  // Repo name = slug(title-at-creation) + "-" + first 10 of the id. Unique; the
  // human-readable part is fixed at creation so a rename never moves the repo.
  function repoName(title, id) { return (slugify(title) || "app") + "-" + String(id || uuid()).slice(0, 10); }

  function bridge(t, path, method, body) {
    var f = (t && t.fetch) || (typeof fetch !== "undefined" ? fetch : null);
    if (!f) return Promise.reject(new Error("no fetch"));
    var url = ((t && t.origin) || "") + "/zeqgit-bridge" + path;
    var headers = { "Content-Type": "application/json" };
    if (t && t.token) headers["Authorization"] = "Bearer " + t.token;
    return f(url, { method: method || "GET", headers: headers, body: body ? JSON.stringify(body) : undefined });
  }
  function defaultReadme(repo) {
    return "# " + repo + "\nZeq project — files, pages & state contracts auto-save here, " +
      "timestamped, with a ZeqProof on each commit. Created " + new Date().toISOString() + "\n";
  }
  // Create+seed the repo if absent (idempotent on the bridge side).
  function ensureRepo(t, repo, readme) {
    return bridge(t, "/repo/ensure", "POST", { project: repo, files: [{ path: "README.md", content: readme || defaultReadme(repo) }] });
  }
  // Commit one file, timestamped. (Standard base64 handled bridge-side.)
  function mirrorFile(t, repo, path, content, msg) {
    return bridge(t, "/repo/file", "PUT", { project: repo, path: path, content: content, message: (msg || ("save " + path)) + " @ " + new Date().toISOString() });
  }
  function listRepos(t) { return bridge(t, "/repo/list", "GET"); }

  // Proof-of-computation links (relative; prefix with origin if cross-surface).
  function observerUrl(slug) { return "/apps/observer/?slug=" + encodeURIComponent(slug || ""); }
  function explorerUrl(slug) { return "/state/?slug=" + encodeURIComponent(slug || ""); }

  return {
    version: "1.0.0",
    slugify: slugify, fnv: fnv, chatId: chatId, uuid: uuid, repoName: repoName,
    bridge: bridge, ensureRepo: ensureRepo, mirrorFile: mirrorFile, listRepos: listRepos,
    defaultReadme: defaultReadme, observerUrl: observerUrl, explorerUrl: explorerUrl,
  };
});
