import { createPublicKey, verify } from "node:crypto";

export const TYPE = "market.mizan.verdict"; // AP2 Mandate Constraint type (carriage for AP2 v0.2 Payment Mandates)
const SPKI = Buffer.from("302a300506032b6570032100", "hex"), b64u = (s: string) => Buffer.from(s, "base64url");
const norm = (s: unknown) => { const v = String(s ?? "").trim(); return v.toLowerCase().startsWith("0x") ? v.toLowerCase() : v; };

/** constraint: {type: TYPE, rule: "sha256:..."}, user-signed in the OPEN Payment Mandate. paymentMandate: the CLOSED Payment
 *  Mandate contents (payee {id, website}). token: the mzv1 verdict presented with it. keys: pinned {kid: base64 Ed25519}. Offline. */
export function ap2VerdictOk(constraint: any, paymentMandate: any, token: string, keys: Record<string, string>, now = Date.now() / 1000) {
  if (constraint?.type !== TYPE || !String(constraint?.rule ?? "").startsWith("sha256:")) return { ok: false, code: "unresolved_constraint" };
  const [pre, body, sig] = String(token ?? "").split("."); let c: any;
  try { c = JSON.parse(b64u(body).toString("utf8")); } catch { return { ok: false, code: "malformed" }; }
  if (pre !== "mzv1" || !keys[c?.kid]) return { ok: false, code: pre !== "mzv1" ? "malformed" : "unknown_kid" };
  const key = createPublicKey({ key: Buffer.concat([SPKI, Buffer.from(keys[c.kid], "base64")]), format: "der", type: "spki" });
  if (!verify(null, Buffer.from(`${pre}.${body}`, "ascii"), key, b64u(sig ?? ""))) return { ok: false, code: "bad_signature" };
  if (c.typ !== "mizan.verdict/1") return { ok: false, code: "malformed" };
  if (!(c.exp > now)) return { ok: false, code: "expired" };
  const p = paymentMandate?.payee ?? {}, ids = [norm(p.id), norm(p.website)].filter(Boolean);
  if (!c.bound_to || !ids.includes(norm(c.bound_to.payee))) return { ok: false, code: "payee_mismatch" };
  if (c.rule !== constraint.rule || c.bound_to.rule !== constraint.rule) return { ok: false, code: "rule_mismatch" };
  return c.decision === "ALLOW" ? { ok: true, code: "valid" } : { ok: false, code: "refused" };
}
