import { canonicalize, sha256Bytes, utf8 } from "./crypto";
import { HttpError, type JsonObject, type JsonValue } from "./types";

export function json(value: JsonValue, status = 200, headers?: HeadersInit): Response {
  return new Response(`${canonicalize(value)}\n`, {
    status,
    headers: {
      "content-type": "application/json; charset=utf-8",
      "cache-control": "no-store",
      "x-content-type-options": "nosniff",
      ...headers,
    },
  });
}

export async function requestDigest(value: JsonValue): Promise<string> {
  return sha256Bytes(utf8(canonicalize(value)));
}

export function errorResponse(error: unknown): Response {
  if (error instanceof HttpError) {
    return json({ error: { code: error.code, message: error.message } }, error.status);
  }
  return json(
    { error: { code: "INTERNAL_ERROR", message: "request could not be completed" } },
    500,
  );
}

export function requireIdempotencyKey(request: Request): string {
  const value = requireHeader(request, "Idempotency-Key");
  if (value.length < 16 || value.length > 128 || !/^[\x20-\x7e]+$/u.test(value)) {
    throw new HttpError(
      400,
      "INVALID_IDEMPOTENCY_KEY",
      "Idempotency-Key must be 16 to 128 visible ASCII characters",
    );
  }
  return value;
}

export function requireCreationCapability(request: Request): string {
  const value = requireHeader(request, "Idempotency-Key");
  if (
    !/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u.test(
      value,
    )
  ) {
    throw new HttpError(
      400,
      "INVALID_CREATION_CAPABILITY",
      "run creation requires an unguessable UUIDv4 Idempotency-Key",
    );
  }
  return value;
}

export function requireHeader(request: Request, name: string): string {
  const value = request.headers.get(name)?.trim();
  if (!value) throw new HttpError(400, "MISSING_HEADER", `${name} is required`);
  if (value.length > 256 || /[\u0000-\u001f\u007f]/u.test(value)) {
    throw new HttpError(400, "INVALID_HEADER", `${name} is malformed`);
  }
  return value;
}

export function bearer(request: Request): string {
  const authorization = request.headers.get("authorization");
  if (authorization === null || !authorization.startsWith("Bearer ")) {
    throw new HttpError(401, "UNAUTHORIZED", "Bearer run capability is required");
  }
  const token = authorization.slice(7);
  if (!/^[A-Za-z0-9_-]{40,128}$/u.test(token)) {
    throw new HttpError(401, "UNAUTHORIZED", "Bearer run capability is malformed");
  }
  return token;
}

export function publicSummary(state: {
  run_id: string;
  status: string;
  decisions: {
    scenario: string;
    request_id: string;
    decision: string;
    decision_attestation: string;
    receipt: { action: { subject: { decision_event_id?: JsonValue } } };
  }[];
  effects: {
    mediated: boolean;
    observation_id: string;
    request_id: string;
    operation_ref: string;
  }[];
  observation_receipts?: {
    action: { subject: { observation_id?: JsonValue } };
    hashes: { attestation: string };
  }[];
}): JsonObject {
  return {
    run_id: state.run_id,
    status: state.status,
    scenario: {
      requests: state.decisions.length,
      mediated_effects: state.effects.filter((effect) => effect.mediated).length,
      direct_effects: state.effects.filter((effect) => !effect.mediated).length,
    },
    decisions: state.decisions.map((decision) => ({
      scenario: decision.scenario,
      request_id: decision.request_id,
      decision: decision.decision,
      decision_event_id: decision.receipt.action.subject.decision_event_id ?? null,
      decision_attestation: decision.decision_attestation,
    })),
    effects: state.effects.map((effect) => ({
      observation_id: effect.observation_id,
      request_id: effect.request_id,
      path: effect.mediated ? "MEDIATED" : "DIRECT_BYPASS",
      operation_ref: effect.operation_ref,
      observation_attestation:
        state.observation_receipts?.find(
          (receipt) => receipt.action.subject.observation_id === effect.observation_id,
        )?.hashes.attestation ?? null,
    })),
    links: {
      coverage: `/experimental/v1/runs/${state.run_id}/coverage`,
      packet_manifest: `/experimental/v1/runs/${state.run_id}/packet/manifest`,
    },
  };
}
