const textEncoder = new TextEncoder();
const textDecoder = new TextDecoder();
const CLAIM_HEARTBEAT = Symbol("suvenraClaimHeartbeat");
const CANONICAL_SERVICE_ORIGIN = "https://suvenra.com";
const PREVIOUS_BRAND = ["v", "s", "e", "l", "f"].join("");
const PREVIOUS_CONNECTOR_TYPE = `${PREVIOUS_BRAND.toUpperCase()}AgentConnector`;
const PREVIOUS_SERVICE_HOSTS = new Set([
  `${PREVIOUS_BRAND}.com`,
  `www.${PREVIOUS_BRAND}.com`,
  `${PREVIOUS_BRAND}-mars-01.alsoraoige.chatgpt.site`,
]);
const PREVIOUS_PATH_ROOT = `/${PREVIOUS_BRAND}`;
const PREVIOUS_EXACT_PATHS = new Map([
  [`/api/${PREVIOUS_BRAND}/protocol`, "/api/suvenra/protocol"],
  [`/${PREVIOUS_BRAND}-agent-client.mjs`, "/suvenra-agent-client.mjs"],
]);
const SUPPORTED_SERVICE_DIDS = new Set([
  "did:web:suvenra.com",
]);

function canonicalSuvenraPathname(pathname) {
  const exactPath = PREVIOUS_EXACT_PATHS.get(pathname);
  if (exactPath) return exactPath;
  if (pathname === PREVIOUS_PATH_ROOT) return "/workspace";
  if (pathname.startsWith(`${PREVIOUS_PATH_ROOT}/`)) {
    const unprefixedPath = pathname.slice(PREVIOUS_PATH_ROOT.length);
    if (
      unprefixedPath === "/delegate"
      || unprefixedPath.startsWith("/delegate/")
    ) {
      return `/authorize${unprefixedPath.slice("/delegate".length)}`;
    }
    return unprefixedPath;
  }
  return pathname;
}

function canonicalSuvenraUrl(value) {
  if (typeof value !== "string" || !value.trim()) return value;
  const input = value.trim();
  const isAbsolute = /^[a-z][a-z\d+.-]*:/iu.test(input) || input.startsWith("//");
  try {
    const url = new URL(input, CANONICAL_SERVICE_ORIGIN);
    const hostname = url.hostname.toLowerCase().replace(/\.$/u, "");
    const previousHost = PREVIOUS_SERVICE_HOSTS.has(hostname);
    const currentHost = hostname === "suvenra.com" || hostname === "www.suvenra.com";
    const localHost = hostname === "localhost" || hostname === "127.0.0.1";
    if (isAbsolute && !previousHost && !currentHost && !localHost) return value;

    url.pathname = canonicalSuvenraPathname(url.pathname);
    if (previousHost || currentHost) {
      url.protocol = "https:";
      url.hostname = "suvenra.com";
      url.port = "";
    }
    return isAbsolute ? url.toString() : `${url.pathname}${url.search}${url.hash}`;
  } catch {
    return value;
  }
}

function bytesFromBase64Url(value) {
  const padded = value.replaceAll("-", "+").replaceAll("_", "/")
    .padEnd(Math.ceil(value.length / 4) * 4, "=");
  const binary = atob(padded);
  return Uint8Array.from(binary, (character) => character.charCodeAt(0));
}

function bytesToBase64Url(bytes) {
  let binary = "";
  bytes.forEach((byte) => {
    binary += String.fromCharCode(byte);
  });
  return btoa(binary)
    .replaceAll("+", "-")
    .replaceAll("/", "_")
    .replace(/=+$/g, "");
}

function randomCapability() {
  return bytesToBase64Url(crypto.getRandomValues(new Uint8Array(32)));
}

function normalize(value) {
  if (Array.isArray(value)) return value.map(normalize);
  if (value && typeof value === "object") {
    return Object.fromEntries(
      Object.entries(value)
        .sort(([left], [right]) => left.localeCompare(right))
        .map(([key, item]) => [key, normalize(item)]),
    );
  }
  return value;
}

function stableStringify(value) {
  return JSON.stringify(normalize(value));
}

async function sha256Hex(value) {
  const digest = await crypto.subtle.digest("SHA-256", textEncoder.encode(value));
  return Array.from(new Uint8Array(digest), (byte) =>
    byte.toString(16).padStart(2, "0")).join("");
}

async function decrypt(payload, encodedKey) {
  const rawKey = bytesFromBase64Url(encodedKey);
  if (rawKey.length !== 32) throw new Error("invalid_suvenra_encryption_key");
  const key = await crypto.subtle.importKey(
    "raw",
    rawKey,
    { name: "AES-GCM" },
    false,
    ["decrypt"],
  );
  const plaintext = await crypto.subtle.decrypt(
    { name: "AES-GCM", iv: bytesFromBase64Url(payload.iv) },
    key,
    bytesFromBase64Url(payload.ciphertext),
  );
  return JSON.parse(textDecoder.decode(plaintext));
}

async function encrypt(value, encodedKey) {
  const rawKey = bytesFromBase64Url(encodedKey);
  if (rawKey.length !== 32) throw new Error("invalid_suvenra_encryption_key");
  const key = await crypto.subtle.importKey(
    "raw",
    rawKey,
    { name: "AES-GCM" },
    false,
    ["encrypt"],
  );
  const iv = crypto.getRandomValues(new Uint8Array(12));
  const ciphertext = await crypto.subtle.encrypt(
    { name: "AES-GCM", iv },
    key,
    textEncoder.encode(JSON.stringify(value)),
  );
  return {
    ciphertext: bytesToBase64Url(new Uint8Array(ciphertext)),
    iv: bytesToBase64Url(iv),
  };
}

function isObject(value) {
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
}

function controllerDidFromJwk(jwk) {
  return `did:jwk:${bytesToBase64Url(textEncoder.encode(stableStringify(jwk)))}`;
}

async function verifyAuthorization(authorization) {
  if (
    !isObject(authorization)
    || authorization.type !== "SuvenraDelegation"
    || !SUPPORTED_SERVICE_DIDS.has(authorization.rootDid)
    || !isObject(authorization.controller)
    || !isObject(authorization.controller.publicKeyJwk)
    || !isObject(authorization.proof)
  ) return false;

  const jwk = authorization.controller.publicKeyJwk;
  const controllerDid = controllerDidFromJwk(jwk);
  if (
    jwk.kty !== "EC"
    || jwk.crv !== "P-256"
    || !jwk.x
    || !jwk.y
    || authorization.controller.id !== controllerDid
    || authorization.controller.kid !== `${controllerDid}#0`
    || authorization.proof.type !== "SuvenraP256Signature2026"
    || authorization.proof.cryptosuite !== "ECDSA-P256-SHA256"
    || authorization.proof.proofPurpose !== "capabilityDelegation"
    || authorization.proof.verificationMethod !== `${controllerDid}#0`
    || typeof authorization.proof.proofValue !== "string"
  ) return false;

  try {
    const publicKey = await crypto.subtle.importKey(
      "jwk",
      jwk,
      { name: "ECDSA", namedCurve: "P-256" },
      false,
      ["verify"],
    );
    const payload = { ...authorization };
    delete payload.proof;
    return crypto.subtle.verify(
      { name: "ECDSA", hash: "SHA-256" },
      publicKey,
      bytesFromBase64Url(authorization.proof.proofValue),
      textEncoder.encode(stableStringify(payload)),
    );
  } catch {
    return false;
  }
}

async function verifyRevocation(statement, authorization) {
  if (
    !isObject(statement)
    || statement.version !== 1
    || statement.type !== "SuvenraRevocation"
    || statement.grantId !== authorization.id
    || !isObject(statement.controller)
    || statement.controller.id !== authorization.controller.id
    || statement.controller.kid !== authorization.controller.kid
    || stableStringify(statement.controller.publicKeyJwk) !== stableStringify(authorization.controller.publicKeyJwk)
    || !isObject(statement.proof)
    || statement.proof.type !== "SuvenraRevocationSignature2026"
    || statement.proof.cryptosuite !== "ECDSA-P256-SHA256"
    || statement.proof.proofPurpose !== "capabilityRevocation"
    || statement.proof.verificationMethod !== authorization.controller.kid
    || statement.proof.created !== statement.revokedAt
    || !Number.isFinite(Date.parse(statement.revokedAt))
  ) return false;
  try {
    const key = await crypto.subtle.importKey(
      "jwk",
      authorization.controller.publicKeyJwk,
      { name: "ECDSA", namedCurve: "P-256" },
      false,
      ["verify"],
    );
    const payload = { ...statement };
    delete payload.proof;
    return crypto.subtle.verify(
      { name: "ECDSA", hash: "SHA-256" },
      key,
      bytesFromBase64Url(statement.proof.proofValue),
      textEncoder.encode(stableStringify(payload)),
    );
  } catch {
    return false;
  }
}

async function authorizationIsRevoked(authorization, config, request) {
  const endpointValue = authorization.status?.revocationEndpoint;
  if (typeof endpointValue !== "string") return false;
  let endpoint;
  let protocol;
  let inbox;
  try {
    endpoint = new URL(canonicalSuvenraUrl(endpointValue));
    protocol = new URL(config.protocolUrl);
    inbox = new URL(config.inboxUrl);
  } catch {
    throw new Error("suvenra_revocation_endpoint_invalid");
  }
  const prefix = "/api/revocations/";
  if (!endpoint.pathname.startsWith(prefix)) return false;
  let endpointGrantId;
  try {
    endpointGrantId = decodeURIComponent(endpoint.pathname.slice(prefix.length));
  } catch {
    throw new Error("suvenra_revocation_endpoint_invalid");
  }
  const endpointController = endpoint.searchParams.get("controller");
  if (
    endpointGrantId !== authorization.id
    || (endpointController !== null && endpointController !== authorization.controller.id)
  ) throw new Error("suvenra_revocation_endpoint_invalid");
  if (endpoint.origin !== protocol.origin || endpoint.origin !== inbox.origin) {
    throw new Error("suvenra_revocation_endpoint_invalid");
  }
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), 5_000);
  try {
    const response = await request(endpoint.toString(), {
      cache: "no-store",
      signal: controller.signal,
    });
    if (!response.ok) throw new Error("suvenra_revocation_status_unavailable");
    const body = await response.json();
    if (body?.grantId !== authorization.id || !Array.isArray(body.revocations)) {
      throw new Error("suvenra_revocation_status_unavailable");
    }
    for (const statement of body.revocations) {
      if (
        statement?.grantId !== authorization.id
        || statement?.controller?.id !== authorization.controller.id
      ) continue;
      if (!await verifyRevocation(statement, authorization)) {
        throw new Error("suvenra_revocation_status_unavailable");
      }
      return true;
    }
    return false;
  } catch (error) {
    if (error?.message === "suvenra_revocation_status_unavailable") throw error;
    throw new Error("suvenra_revocation_status_unavailable");
  } finally {
    clearTimeout(timer);
  }
}

function parseTaskRoomAccess(agentUrl, config) {
  let url;
  let inboxUrl;
  try {
    url = new URL(canonicalSuvenraUrl(agentUrl));
    inboxUrl = new URL(config.inboxUrl);
  } catch {
    throw new Error("invalid_suvenra_task_room_url");
  }
  const match = url.pathname.match(/^\/room\/(room_[a-f0-9]{32})$/);
  const hash = new URLSearchParams(url.hash.slice(1));
  const token = hash.get("t")?.trim() || "";
  const encryptionKey = hash.get("k")?.trim() || "";
  if (
    !match
    || url.origin !== inboxUrl.origin
    || !/^[A-Za-z0-9_-]{32,128}$/.test(token)
    || bytesFromBase64Url(encryptionKey).length !== 32
  ) throw new Error("invalid_suvenra_task_room_url");
  return {
    roomId: match[1],
    apiUrl: `${url.origin}/api/rooms/${encodeURIComponent(match[1])}`,
    token,
    encryptionKey,
  };
}

function assertConfig(config) {
  const candidate = isObject(config)
    ? {
        ...config,
        type: config.type === PREVIOUS_CONNECTOR_TYPE
          ? "SuvenraAgentConnector"
          : config.type,
        inboxUrl: canonicalSuvenraUrl(config.inboxUrl),
        protocolUrl: canonicalSuvenraUrl(config.protocolUrl),
        runtimeSessionsUrl: config.runtimeSessionsUrl
          ? canonicalSuvenraUrl(config.runtimeSessionsUrl)
          : config.runtimeSessionsUrl,
      }
    : config;
  let inbox;
  let protocol;
  let runtimeSessions;
  try {
    inbox = new URL(candidate?.inboxUrl);
    protocol = new URL(candidate?.protocolUrl);
    runtimeSessions = new URL(
      candidate?.runtimeSessionsUrl || `${inbox.origin}${inbox.pathname}/runtime`,
    );
  } catch {
    throw new Error("invalid_suvenra_connector_config");
  }
  const localDevelopment = inbox.hostname === "localhost" || inbox.hostname === "127.0.0.1";
  if (
    !candidate
    || candidate.type !== "SuvenraAgentConnector"
    || ![1, 2, 3, 4].includes(candidate.version)
    || !/^agent_[a-f0-9]{32}$/.test(candidate.connectionId || "")
    || !/^[A-Za-z0-9_-]{32,128}$/.test(candidate.bearerToken || "")
    || typeof candidate.encryptionKey !== "string"
    || (inbox.protocol !== "https:" && !localDevelopment)
    || inbox.username
    || inbox.password
    || inbox.search
    || inbox.hash
    || inbox.pathname !== `/api/agents/${candidate.connectionId}`
    || protocol.origin !== inbox.origin
    || protocol.pathname !== "/api/suvenra/protocol"
    || protocol.search
    || protocol.hash
    || runtimeSessions.origin !== inbox.origin
    || runtimeSessions.pathname !== `${inbox.pathname}/runtime`
    || runtimeSessions.search
    || runtimeSessions.hash
    || (candidate.version === 4 && !candidate.runtimeSessionsUrl)
    || !isObject(candidate.agent)
    || typeof candidate.agent.name !== "string"
    || !candidate.agent.name.trim()
    || typeof candidate.agent.did !== "string"
    || !candidate.agent.did.trim()
    || !Number.isFinite(Date.parse(candidate.createdAt || ""))
    || (candidate.credentialVersion !== undefined
      && (!Number.isInteger(candidate.credentialVersion) || candidate.credentialVersion < 1))
  ) throw new Error("invalid_suvenra_connector_config");
  if (bytesFromBase64Url(candidate.encryptionKey).length !== 32) {
    throw new Error("invalid_suvenra_connector_config");
  }
  if (
    (candidate.encryptionKeyId !== undefined
      && !/^key_[a-f0-9]{16,32}$/.test(candidate.encryptionKeyId))
    || (candidate.version === 3 && !candidate.encryptionKeyId)
    || (candidate.encryptionKeys !== undefined && (
      !Array.isArray(candidate.encryptionKeys)
      || candidate.encryptionKeys.length > 16
      || candidate.encryptionKeys.some((entry) =>
        !isObject(entry)
        || !/^key_[a-f0-9]{16,32}$/.test(entry.id || "")
        || typeof entry.key !== "string"
        || bytesFromBase64Url(entry.key).length !== 32
        || !Number.isFinite(Date.parse(entry.createdAt || "")))
    ))
  ) throw new Error("invalid_suvenra_connector_config");
  return { ...candidate, runtimeSessionsUrl: runtimeSessions.toString() };
}

function encryptionKeyForDelivery(config, delivery) {
  const keyId = delivery?.encryptionKeyId || null;
  if (!keyId || keyId === config.encryptionKeyId) return config.encryptionKey;
  const match = (config.encryptionKeys || []).find((entry) => entry?.id === keyId);
  if (!match || typeof match.key !== "string") return null;
  return match.key;
}

function waitForNextPoll(intervalMs, signal) {
  if (signal?.aborted) return Promise.resolve();
  return new Promise((resolve) => {
    let settled = false;
    const finish = () => {
      if (settled) return;
      settled = true;
      clearTimeout(timer);
      signal?.removeEventListener("abort", finish);
      resolve();
    };
    const timer = setTimeout(finish, Math.max(2_000, intervalMs));
    signal?.addEventListener("abort", finish, { once: true });
  });
}

export class SuvenraTaskRoomClient {
  constructor(agentUrl, connectorConfig, options = {}) {
    this.config = assertConfig(connectorConfig);
    if (!isObject(this.config.agent) || typeof this.config.agent.did !== "string") {
      throw new Error("suvenra_agent_identity_required");
    }
    this.fetch = options.fetch || globalThis.fetch;
    if (typeof this.fetch !== "function") throw new Error("fetch_unavailable");
    this.access = parseTaskRoomAccess(agentUrl, this.config);
    this.expectedGrantId = options.expectedGrantId || null;
    this.expectedRoomId = options.expectedRoomId || null;
    this.state = null;
  }

  get authorization() {
    return this.state?.authorization || null;
  }

  get status() {
    return this.state?.status || null;
  }

  async request(init = {}) {
    const response = await this.fetch(this.access.apiUrl, {
      ...init,
      headers: {
        Authorization: `Bearer ${this.access.token}`,
        ...(init.body ? { "Content-Type": "application/json" } : {}),
        ...init.headers,
      },
    });
    const body = await response.json().catch(() => ({}));
    if (!response.ok) {
      const error = new Error(body.error || `suvenra_room_request_${response.status}`);
      error.status = response.status;
      error.body = body;
      throw error;
    }
    return body;
  }

  async decodeRoom(room) {
    if (
      !isObject(room)
      || room.role !== "agent"
      || room.id !== this.access.roomId
      || (this.expectedRoomId && room.id !== this.expectedRoomId)
    ) throw new Error("suvenra_task_room_mismatch");

    const authorization = await decrypt(room.authorization, this.access.encryptionKey);
    const authorizationHash = await sha256Hex(stableStringify(authorization));
    if (authorizationHash !== room.authorizationHash) {
      throw new Error("suvenra_authorization_hash_mismatch");
    }
    if (!await verifyAuthorization(authorization)) {
      throw new Error("suvenra_authorization_signature_invalid");
    }
    if (await authorizationIsRevoked(authorization, this.config, this.fetch)) {
      throw new Error("suvenra_authorization_revoked");
    }
    if (
      !isObject(authorization.grantedTo)
      || !isObject(authorization.scope)
      || typeof authorization.scope.task !== "string"
      || typeof authorization.scope.evidence !== "string"
      || (this.config.agent?.did && authorization.grantedTo.did !== this.config.agent.did)
      || (this.expectedGrantId && authorization.id !== this.expectedGrantId)
    ) throw new Error("suvenra_authorization_scope_mismatch");

    const issuedAt = Date.parse(authorization.issuedAt);
    const expiresAt = Date.parse(authorization.expiresAt);
    const now = Date.now();
    if (
      !Number.isFinite(issuedAt)
      || !Number.isFinite(expiresAt)
      || expiresAt <= issuedAt
      || issuedAt > now + 5 * 60 * 1000
      || expiresAt <= now
      || room.status === "expired"
      || room.status === "revoked"
    ) throw new Error("suvenra_authorization_inactive");

    const events = await Promise.all((room.events || []).map(async (event) => ({
      ...event,
      data: event.payload
        ? await decrypt(event.payload, this.access.encryptionKey)
        : null,
    })));
    this.state = {
      ...room,
      authorization,
      authorizationValid: true,
      events,
    };
    return this.state;
  }

  async read() {
    const body = await this.request({ cache: "no-store" });
    if (!body.room) throw new Error("suvenra_task_room_missing");
    return this.decodeRoom(body.room);
  }

  async transition(action, value, allowedStatuses, options = {}) {
    const current = await this.read();
    if (!allowedStatuses.includes(current.status)) {
      throw new Error("suvenra_task_room_state_changed");
    }
    const payload = value == null
      ? null
      : await encrypt(value, this.access.encryptionKey);
    const body = await this.request({
      method: "PATCH",
      body: JSON.stringify({
        action,
        payload,
        commitmentHash: options.commitmentHash || null,
      }),
    });
    if (!body.room) throw new Error("suvenra_task_room_missing");
    return this.decodeRoom(body.room);
  }

  async accept() {
    return this.transition("accept", null, ["pending"]);
  }

  async requestChanges(note) {
    const value = String(note || "").trim();
    if (!value) throw new Error("suvenra_change_request_required");
    return this.transition("request_changes", { note: value }, ["pending"]);
  }

  async decline(note = "") {
    const value = String(note || "").trim();
    return this.transition(
      "decline",
      value ? { note: value } : null,
      ["pending", "accepted"],
    );
  }

  async submit({ summary, evidence } = {}) {
    const resultSummary = String(summary || "").trim();
    const resultEvidence = String(evidence || "").trim();
    if (!resultSummary || !resultEvidence) {
      throw new Error("suvenra_result_and_evidence_required");
    }
    const result = { summary: resultSummary, evidence: resultEvidence };
    return this.transition(
      "submit_result",
      result,
      ["accepted"],
      { commitmentHash: await sha256Hex(stableStringify(result)) },
    );
  }

  encryptForReview(value) {
    return encrypt(value, this.access.encryptionKey);
  }
}

export class SuvenraControlledSession {
  constructor(descriptor, options = {}) {
    if (!isObject(descriptor)) throw new Error("invalid_suvenra_controlled_session");
    let actionUrl;
    let completeUrl;
    try {
      actionUrl = new URL(descriptor.actionUrl);
      completeUrl = new URL(descriptor.completeUrl);
    } catch {
      throw new Error("invalid_suvenra_controlled_session");
    }
    const local = actionUrl.hostname === "localhost" || actionUrl.hostname === "127.0.0.1";
    if (
      !/^session_[a-f0-9]{32}$/.test(descriptor.id || "")
      || !/^space_[a-f0-9]{32}$/.test(descriptor.spaceId || "")
      || !/^room_[a-f0-9]{32}$/.test(descriptor.roomId || "")
      || !["browser", "file", "code"].includes(descriptor.runtime)
      || !["running", "paused", "takeover", "waiting_approval"].includes(descriptor.status)
      || !/^[a-f0-9]{64}$/.test(descriptor.policyHash || "")
      || !/^[A-Za-z0-9_-]{43}$/.test(descriptor.capability || "")
      || (actionUrl.protocol !== "https:" && !local)
      || actionUrl.origin !== completeUrl.origin
      || !actionUrl.pathname.endsWith("/actions")
      || !completeUrl.pathname.endsWith("/complete")
      || actionUrl.username
      || actionUrl.password
      || actionUrl.search
      || actionUrl.hash
      || completeUrl.username
      || completeUrl.password
      || completeUrl.search
      || completeUrl.hash
    ) throw new Error("invalid_suvenra_controlled_session");
    this.descriptor = descriptor;
    this.fetch = options.fetch || globalThis.fetch;
    if (typeof this.fetch !== "function") throw new Error("fetch_unavailable");
  }

  async request(url, body) {
    const response = await this.fetch(url, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${this.descriptor.capability}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(body),
    });
    const value = await response.json().catch(() => ({}));
    if (!response.ok && response.status !== 202) {
      const error = new Error(value.error || `suvenra_runtime_request_${response.status}`);
      error.status = response.status;
      error.body = value;
      throw error;
    }
    return value;
  }

  async act(action, parameters, options = {}) {
    if (typeof action !== "string" || !isObject(parameters)) {
      throw new Error("invalid_suvenra_runtime_action");
    }
    const detail = options.detail
      || (options.task instanceof SuvenraTaskRoomClient && options.reviewDetails !== undefined
        ? await options.task.encryptForReview(options.reviewDetails)
        : null);
    return this.request(this.descriptor.actionUrl, {
      clientEventId: options.clientEventId || `agent:${randomCapability()}`,
      action,
      parameters,
      detailCiphertext: detail?.ciphertext ?? null,
      detailIv: detail?.iv ?? null,
      estimatedCostMicrousd: options.estimatedCostMicrousd ?? 0,
      approvalId: options.approvalId ?? null,
    });
  }

  readFile(path, options = {}) {
    return this.act("read_file", { path }, options);
  }

  writeFile(path, content, options = {}) {
    return this.act("write_file", { path, content }, options);
  }

  runCommand(command, options = {}) {
    return this.act("run_command", {
      command,
      cwd: options.cwd || "/workspace",
    }, options);
  }

  readPage(url, options = {}) {
    return this.act("read_page", { url }, options);
  }

  async completeWithTask(task, { summary, evidence } = {}) {
    if (!(task instanceof SuvenraTaskRoomClient)) throw new Error("suvenra_task_room_required");
    const result = {
      summary: String(summary || "").trim(),
      evidence: String(evidence || "").trim(),
    };
    if (!result.summary || !result.evidence) {
      throw new Error("suvenra_result_and_evidence_required");
    }
    const evidenceHash = await sha256Hex(stableStringify(result));
    const submitted = await task.submit(result);
    const submittedEvent = [...(submitted.events || [])]
      .reverse()
      .find((event) => event.type === "submit_result");
    if (submittedEvent?.commitmentHash !== evidenceHash) {
      throw new Error("suvenra_result_commitment_mismatch");
    }
    const encrypted = await encrypt(result, task.access.encryptionKey);
    return this.request(this.descriptor.completeUrl, {
      resultCiphertext: encrypted.ciphertext,
      resultIv: encrypted.iv,
      evidenceHash,
    });
  }
}

export class SuvenraAgentClient {
  static async connect(setupUrl, options = {}) {
    const url = new URL(canonicalSuvenraUrl(setupUrl));
    const code = new URLSearchParams(url.hash.slice(1)).get("code")?.trim() || "";
    if (
      !/^\/api\/agents\/agent_[a-f0-9]{32}\/onboarding\/setup_[a-f0-9]{32}$/.test(url.pathname)
      || !/^[A-Za-z0-9_-]{43}$/.test(code)
      || (url.protocol !== "https:" && url.hostname !== "localhost" && url.hostname !== "127.0.0.1")
    ) throw new Error("invalid_suvenra_setup_url");
    url.hash = "";
    const request = options.fetch || globalThis.fetch;
    if (typeof request !== "function") throw new Error("fetch_unavailable");
    const response = await request(url.toString(), {
      cache: "no-store",
      headers: { Authorization: `Bearer ${code}` },
    });
    const body = await response.json().catch(() => ({}));
    if (!response.ok || !body.setup?.payload) {
      const error = new Error(body.error || `suvenra_setup_request_${response.status}`);
      error.status = response.status;
      error.body = body;
      throw error;
    }
    const config = await decrypt(body.setup.payload, code);
    const payloadHash = await sha256Hex(stableStringify(config));
    if (payloadHash !== body.setup.payloadHash) throw new Error("suvenra_setup_hash_mismatch");
    if (new URL(assertConfig(config).inboxUrl).origin !== url.origin) {
      throw new Error("suvenra_setup_origin_mismatch");
    }
    return new SuvenraAgentClient(config, options);
  }

  constructor(config, options = {}) {
    this.config = assertConfig(config);
    this.fetch = options.fetch || globalThis.fetch;
    if (typeof this.fetch !== "function") throw new Error("fetch_unavailable");
  }

  async request(url, init = {}) {
    const response = await this.fetch(url, {
      ...init,
      headers: {
        Authorization: `Bearer ${this.config.bearerToken}`,
        ...(init.body ? { "Content-Type": "application/json" } : {}),
        ...init.headers,
      },
    });
    const body = await response.json().catch(() => ({}));
    if (!response.ok) {
      const error = new Error(body.error || `suvenra_request_${response.status}`);
      error.status = response.status;
      error.body = body;
      throw error;
    }
    return body;
  }

  async acknowledge(deliveryId, action, details = {}) {
    if (!["receive", "open", "claim", "renew", "complete", "release"].includes(action)) {
      throw new Error("invalid_suvenra_acknowledgement");
    }
    return this.request(
      `${this.config.inboxUrl}/deliveries/${encodeURIComponent(deliveryId)}`,
      { method: "PATCH", body: JSON.stringify({ action, ...details }) },
    );
  }

  async readInbox({ acknowledgeReceived = true } = {}) {
    const body = await this.request(this.config.inboxUrl, { cache: "no-store" });
    const deliveries = await Promise.all(
      (body.connection?.deliveries || []).map(async (delivery) => {
        if (delivery.status === "expired") return { ...delivery, data: null };
        const encryptionKey = encryptionKeyForDelivery(this.config, delivery);
        if (!encryptionKey) return { ...delivery, data: null, keyUnavailable: true };
        const data = await decrypt(delivery.payload, encryptionKey);
        const hash = await sha256Hex(stableStringify(data));
        if (hash !== delivery.payloadHash) throw new Error("suvenra_delivery_hash_mismatch");
        if (acknowledgeReceived && delivery.status === "delivered") {
          await this.acknowledge(delivery.id, "receive");
        }
        return { ...delivery, data };
      }),
    );
    return { ...body.connection, deliveries };
  }

  async readControlledSessions() {
    const body = await this.request(this.config.runtimeSessionsUrl, { cache: "no-store" });
    return (body.sessions || []).map((session) =>
      new SuvenraControlledSession(session, { fetch: this.fetch }));
  }

  async open(delivery) {
    const claimed = delivery.status === "claimed" && delivery.claimToken
      ? delivery
      : await this.claim(delivery);
    const encryptionKey = encryptionKeyForDelivery(this.config, claimed);
    if (!encryptionKey) throw new Error("suvenra_delivery_key_unavailable");
    const data = claimed.data ?? await decrypt(claimed.payload, encryptionKey);
    const hash = await sha256Hex(stableStringify(data));
    if (hash !== claimed.payloadHash) throw new Error("suvenra_delivery_hash_mismatch");
    return data;
  }

  async claim(delivery, { leaseSeconds = 120 } = {}) {
    if (!delivery?.id) throw new Error("invalid_suvenra_delivery");
    if (delivery.status === "completed" || delivery.status === "opened" || delivery.status === "expired") {
      throw new Error("suvenra_delivery_not_claimable");
    }
    const claimToken = randomCapability();
    const body = await this.acknowledge(delivery.id, "claim", { claimToken, leaseSeconds });
    const claimed = { ...delivery, ...body.delivery, claimToken };
    const encryptionKey = encryptionKeyForDelivery(this.config, claimed);
    if (!encryptionKey) {
      await this.release(claimed).catch(() => {});
      throw new Error("suvenra_delivery_key_unavailable");
    }
    const data = delivery.data ?? await decrypt(claimed.payload, encryptionKey);
    const hash = await sha256Hex(stableStringify(data));
    if (hash !== claimed.payloadHash) {
      await this.release(claimed).catch(() => {});
      throw new Error("suvenra_delivery_hash_mismatch");
    }
    return { ...claimed, data, idempotencyKey: claimed.idempotencyKey || claimed.id };
  }

  async complete(delivery) {
    if (!delivery?.claimToken) throw new Error("suvenra_delivery_claim_required");
    return this.acknowledge(delivery.id, "complete", { claimToken: delivery.claimToken });
  }

  async renew(delivery, { leaseSeconds = 120 } = {}) {
    if (!delivery?.claimToken) throw new Error("suvenra_delivery_claim_required");
    return this.acknowledge(delivery.id, "renew", {
      claimToken: delivery.claimToken,
      leaseSeconds,
    });
  }

  async release(delivery) {
    if (!delivery?.claimToken) throw new Error("suvenra_delivery_claim_required");
    return this.acknowledge(delivery.id, "release", { claimToken: delivery.claimToken });
  }

  startClaimHeartbeat(delivery, { leaseSeconds = 120 } = {}) {
    const normalizedLease = Math.min(300, Math.max(30, Math.round(Number(leaseSeconds) || 120)));
    const remainingMs = Date.parse(delivery.leaseExpiresAt || "") - Date.now();
    const renewalWindowMs = Number.isFinite(remainingMs) && remainingMs > 0
      ? Math.min(normalizedLease * 1_000, remainingMs)
      : normalizedLease * 1_000;
    const intervalMs = Math.max(1_000, Math.floor(renewalWindowMs / 3));
    const stopController = new AbortController();
    const claimController = new AbortController();
    let failure = null;
    const done = (async () => {
      while (!stopController.signal.aborted) {
        await waitForNextPoll(intervalMs, stopController.signal);
        if (stopController.signal.aborted) break;
        try {
          const body = await this.renew(delivery, { leaseSeconds: normalizedLease });
          Object.assign(delivery, body.delivery);
        } catch (error) {
          failure = error;
          claimController.abort(error);
          break;
        }
      }
    })();
    return {
      signal: claimController.signal,
      get error() { return failure; },
      async stop() {
        stopController.abort();
        await done;
      },
    };
  }

  async openTask(delivery) {
    const claimed = delivery.status === "claimed" && delivery.claimToken
      ? delivery
      : await this.claim(delivery);
    const heartbeat = claimed[CLAIM_HEARTBEAT]
      || this.startClaimHeartbeat(claimed);
    claimed[CLAIM_HEARTBEAT] = heartbeat;
    claimed.claimSignal = heartbeat.signal;
    try {
      const data = await this.open(claimed);
      if (
        data?.type !== "SuvenraTaskDelivery"
        || !data.agentUrl
        || !data.grantId
        || !data.roomId
      ) throw new Error("invalid_suvenra_task_delivery");
      const task = new SuvenraTaskRoomClient(data.agentUrl, this.config, {
        fetch: this.fetch,
        expectedGrantId: data.grantId,
        expectedRoomId: data.roomId,
      });
      task.delivery = claimed;
      task.idempotencyKey = claimed.idempotencyKey || claimed.id;
      task.claimSignal = heartbeat.signal;
      task.completeDelivery = async () => {
        await heartbeat.stop();
        if (heartbeat.error) throw heartbeat.error;
        return this.complete(claimed);
      };
      task.releaseDelivery = async () => {
        await heartbeat.stop();
        return this.release(claimed);
      };
      await task.read();
      return task;
    } catch (error) {
      await heartbeat.stop();
      await this.release(claimed).catch(() => {});
      throw error;
    }
  }

  async watch(handler, { intervalMs = 8_000, leaseSeconds = 120, signal, onError } = {}) {
    while (!signal?.aborted) {
      const inbox = await this.readInbox({ acknowledgeReceived: false });
      for (const delivery of inbox.deliveries.slice().reverse()) {
        if (
          delivery.status === "expired"
          || delivery.status === "completed"
          || delivery.status === "opened"
          || delivery.keyUnavailable
        ) continue;
        let claimed;
        try {
          claimed = await this.claim(delivery, { leaseSeconds });
        } catch (error) {
          if (error?.status === 409) continue;
          if (onError) await onError(error, delivery, this);
          else throw error;
          continue;
        }
        const heartbeat = this.startClaimHeartbeat(claimed, { leaseSeconds });
        claimed[CLAIM_HEARTBEAT] = heartbeat;
        claimed.claimSignal = heartbeat.signal;
        try {
          await handler(claimed, this);
          await heartbeat.stop();
          if (heartbeat.error) throw heartbeat.error;
          await this.complete(claimed);
        } catch (error) {
          await heartbeat.stop();
          await this.release(claimed).catch(() => {});
          if (onError) await onError(error, claimed, this);
          else throw error;
        }
      }
      await waitForNextPoll(intervalMs, signal);
    }
  }
}

export default SuvenraAgentClient;
