// ── Control-plane API client ───────────────────────────────────────────────
// Same cookie + CSRF + single-flight-refresh model as the LMS components/api.jsx,
// scoped to /api/cp. Access/refresh cookies are cp_at / cp_rt (host-only).

const CP_BASE = "/api/cp";

function cpCookie(name) {
  const m = document.cookie.match(
    "(?:^|; )" + name.replace(/([.$?*|{}()\[\]\\\/\+^])/g, "\\$1") + "=([^;]*)"
  );
  return m ? decodeURIComponent(m[1]) : null;
}

async function cpEnsureCsrf() {
  let t = cpCookie("cl_csrf");
  if (!t) {
    try {
      const r = await fetch("/api/csrf", { credentials: "include" });
      const d = await r.json();
      t = d.csrfToken || cpCookie("cl_csrf");
    } catch {}
  }
  return t;
}

const CP_UNSAFE = { POST: 1, PUT: 1, PATCH: 1, DELETE: 1 };
const CP_NO_RETRY = /^\/auth\/(login|verify-otp|refresh|logout)(\/|$|\?)/;

let _cpRefresh = null;
function cpRefreshOnce() {
  if (!_cpRefresh) {
    _cpRefresh = fetch(CP_BASE + "/auth/refresh", { method: "POST", credentials: "include" })
      .then((r) => r.ok)
      .catch(() => false)
      .finally(() => { _cpRefresh = null; });
  }
  return _cpRefresh;
}

async function cpFetch(endpoint, opts = {}) {
  const method = (opts.method || "GET").toUpperCase();
  const headers = { "Content-Type": "application/json", ...(opts.headers || {}) };
  if (CP_UNSAFE[method]) {
    const token = cpCookie("cl_csrf") || (await cpEnsureCsrf());
    if (token) headers["X-CSRF-Token"] = token;
  }
  let res = await fetch(CP_BASE + endpoint, { ...opts, headers, credentials: "include" });
  if (res.status === 401 && !opts._retry && !CP_NO_RETRY.test(endpoint)) {
    if (await cpRefreshOnce()) return cpFetch(endpoint, { ...opts, _retry: true });
  }
  return res;
}

async function cpJson(endpoint, method, body) {
  const res = await cpFetch(endpoint, {
    method: method || "GET",
    body: body != null ? JSON.stringify(body) : undefined,
  });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) throw new Error(data.error || `Request failed (${res.status})`);
  return data;
}

const cpApi = {
  // auth — login returns { otpRequired, ticket, email } (password OK, code sent)
  login: (email, password) => cpJson("/auth/login", "POST", { email, password }),
  verifyOtp: (ticket, code) => cpJson("/auth/verify-otp", "POST", { ticket, code }),
  me: () => cpJson("/auth/me"),
  logout: () => cpFetch("/auth/logout", { method: "POST" }),
  changePassword: (currentPassword, newPassword) =>
    cpJson("/auth/change-password", "POST", { currentPassword, newPassword }),
  changeEmail: (newEmail, currentPassword) =>
    cpJson("/auth/email", "PATCH", { newEmail, currentPassword }),
  // dashboard
  getStats: () => cpJson("/stats"),
  // tenants
  flagsCatalog: () => cpJson("/flags-catalog"),
  config: () => cpJson("/config"),
  listTenants: () => cpJson("/tenants"),
  getTenant: (id) => cpJson(`/tenants/${id}`),
  createTenant: (body) => cpJson("/tenants", "POST", body),
  updateTenant: (id, body) => cpJson(`/tenants/${id}`, "PATCH", body),
  provisionTenant: (id) => cpJson(`/tenants/${id}/provision`, "POST"),
  getJob: (jobId) => cpJson(`/jobs/${jobId}`),
  setDomain: (id, customDomain) => cpJson(`/tenants/${id}/domain`, "PATCH", { customDomain }),
  deleteCode: (id, action) => cpJson(`/tenants/${id}/delete-code`, "POST", { action }),
  deleteTenant: (id, body) => cpJson(`/tenants/${id}`, "DELETE", body),
  deleteAtlasProject: (id, body) => cpJson(`/tenants/${id}/atlas/delete-project`, "POST", body),
  tenantHealth: (id) => cpJson(`/tenants/${id}/health`),
  setFlags: (id, flags) => cpJson(`/tenants/${id}/flags`, "PATCH", { flags }),
  setFlag: (id, key, enabled) => cpJson(`/tenants/${id}/flags/${key}`, "PATCH", { enabled }),
  setBranding: (id, branding, logoAssetId) =>
    cpJson(`/tenants/${id}/branding`, "PATCH",
      logoAssetId === undefined ? { branding } : { branding, logoAssetId }),
  setStatus: (id, status) => cpJson(`/tenants/${id}/status`, "PATCH", { status }),
  // contacts (commit 2)
  getContacts: (id) => cpJson(`/tenants/${id}/contacts`),
  addContact: (id, b) => cpJson(`/tenants/${id}/contacts`, "POST", b),
  updateContact: (id, cid, b) => cpJson(`/tenants/${id}/contacts/${cid}`, "PATCH", b),
  deleteContact: (id, cid) => cpJson(`/tenants/${id}/contacts/${cid}`, "DELETE"),
  // admin login (commit 2/3)
  getAdminLogin: (id) => cpJson(`/tenants/${id}/admin-login`),
  resetAdminPassword: (id) => cpJson(`/tenants/${id}/admin-login/reset-password`, "POST"),
  // students (commit 3)
  getStudents: (id, params) =>
    cpJson(`/tenants/${id}/students?` + new URLSearchParams(params || {}).toString()),
  setStudentAccess: (id, sid, locked) =>
    cpJson(`/tenants/${id}/students/${sid}/access`, "PATCH", { locked }),
  resetStudentPassword: (id, sid) =>
    cpJson(`/tenants/${id}/students/${sid}/reset-password`, "POST"),
  // assets (commit 2)
  uploadLogo: (file_name, file_data) => cpJson("/assets/logo", "POST", { file_name, file_data }),
  // operators / templates (commit 3)
  listOperators: () => cpJson("/operators"),
  inviteOperator: (b) => cpJson("/operators", "POST", b),
  updateOperator: (oid, b) => cpJson(`/operators/${oid}`, "PATCH", b),
  resetOperatorPassword: (oid) => cpJson(`/operators/${oid}/reset-password`, "POST"),
  deleteOperator: (oid) => cpJson(`/operators/${oid}`, "DELETE"),
  listTemplates: () => cpJson("/templates"),
  // audit
  audit: (params) => {
    const clean = Object.fromEntries(Object.entries(params || {}).filter(([, v]) => v !== "" && v != null));
    const qs = new URLSearchParams(clean).toString();
    return cpJson("/audit" + (qs ? "?" + qs : ""));
  },
  auditFilters: () => cpJson("/audit/filters"),
};

window.cpApi = cpApi;
window.cpFetch = cpFetch;
