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

export const RUNRAIL_DEVICE_SIGNED_REVIEW_PASSPORT = Object.freeze({
  schemaVersion: 1,
  artifactType: "runrail-device-signed-review-passport",
  profile: "runrail-device-signed-review-passport-v1",
  algorithm: "Ed25519",
  signatureScope: "device-key-possession"
});

function sha256(value) {
  return createHash("sha256").update(value).digest("hex");
}

function stableValue(value) {
  if (Array.isArray(value)) return value.map(stableValue);
  if (value && typeof value === "object") {
    return Object.fromEntries(Object.keys(value).sort().map((key) => [key, stableValue(value[key])]));
  }
  return value;
}

export function stableRunrailPassportJson(value) {
  return `${JSON.stringify(stableValue(value), null, 2)}\n`;
}

function publicKeySha256(value) {
  const key = value?.type === "public" ? value : createPublicKey(value);
  if (key.asymmetricKeyType !== "ed25519") {
    throw new TypeError("A device-signed passport requires an Ed25519 public key.");
  }
  return sha256(key.export({ type: "spki", format: "der" }));
}

export function canonicalRunrailDeviceSignedPassportMessage(passport) {
  verifyRunrailReviewPassport(passport);
  return Buffer.from(
    `runrail-device-signed-review-passport-v1\0${passport.checksumSha256}`,
    "utf8"
  );
}

export function buildRunrailDeviceSignedReviewPassport({
  passport,
  devicePublicKeyPem,
  devicePublicKeySha256,
  signature
}) {
  verifyRunrailReviewPassport(passport);
  if (
    typeof devicePublicKeyPem !== "string" ||
    !devicePublicKeyPem.startsWith("-----BEGIN PUBLIC KEY-----\n") ||
    !devicePublicKeyPem.endsWith("-----END PUBLIC KEY-----\n") ||
    !/^[a-f0-9]{64}$/.test(String(devicePublicKeySha256 || "")) ||
    !/^[A-Za-z0-9_-]{80,128}$/.test(String(signature || ""))
  ) {
    throw new TypeError("The device passport signature metadata is invalid.");
  }
  const publicKey = createPublicKey(devicePublicKeyPem);
  if (
    publicKey.asymmetricKeyType !== "ed25519" ||
    publicKeySha256(publicKey) !== devicePublicKeySha256 ||
    !verifyBytes(
      null,
      canonicalRunrailDeviceSignedPassportMessage(passport),
      publicKey,
      Buffer.from(signature, "base64url")
    )
  ) {
    throw new TypeError("The device passport signature is invalid.");
  }
  const body = {
    schemaVersion: RUNRAIL_DEVICE_SIGNED_REVIEW_PASSPORT.schemaVersion,
    artifactType: RUNRAIL_DEVICE_SIGNED_REVIEW_PASSPORT.artifactType,
    profile: RUNRAIL_DEVICE_SIGNED_REVIEW_PASSPORT.profile,
    product: "Runrail Local v1",
    passport,
    passportChecksumSha256: passport.checksumSha256,
    signature: {
      algorithm: RUNRAIL_DEVICE_SIGNED_REVIEW_PASSPORT.algorithm,
      scope: RUNRAIL_DEVICE_SIGNED_REVIEW_PASSPORT.signatureScope,
      devicePublicKeyPem,
      devicePublicKeySha256,
      value: signature
    },
    claims: {
      deviceKeyPossessionProven: true,
      organizationalIdentityProven: false,
      complianceCertificationProven: false,
      codeCorrectnessProven: false,
      mergeApprovalGranted: false
    },
    boundaries: {
      pathFree: true,
      sourceContentIncluded: false,
      diffContentIncluded: false,
      changedPathsIncluded: false,
      commitIdentifiersIncluded: false,
      repositoryIdentityIncluded: false,
      rawVerifierOutputIncluded: false,
      authority: "none",
      projectTestsExecuted: false,
      securityReviewPerformed: false,
      automaticSourceApplyEnabled: false,
      learnedRuntimeAuthorityAdded: false
    }
  };
  return {
    ...body,
    checksumSha256: sha256(stableRunrailPassportJson(body))
  };
}

export function verifyRunrailDeviceSignedReviewPassport(envelope) {
  if (!exactKeys(envelope, [
    "schemaVersion",
    "artifactType",
    "profile",
    "product",
    "passport",
    "passportChecksumSha256",
    "signature",
    "claims",
    "boundaries",
    "checksumSha256"
  ])) {
    throw new TypeError("The device-signed passport field set is invalid.");
  }
  const { checksumSha256, ...body } = envelope;
  if (
    envelope.schemaVersion !== RUNRAIL_DEVICE_SIGNED_REVIEW_PASSPORT.schemaVersion ||
    envelope.artifactType !== RUNRAIL_DEVICE_SIGNED_REVIEW_PASSPORT.artifactType ||
    envelope.profile !== RUNRAIL_DEVICE_SIGNED_REVIEW_PASSPORT.profile ||
    envelope.product !== "Runrail Local v1" ||
    !/^[a-f0-9]{64}$/.test(String(checksumSha256 || "")) ||
    checksumSha256 !== sha256(stableRunrailPassportJson(body))
  ) {
    throw new TypeError("The device-signed passport identity or checksum is invalid.");
  }
  verifyRunrailReviewPassport(envelope.passport);
  if (envelope.passportChecksumSha256 !== envelope.passport.checksumSha256) {
    throw new TypeError("The device-signed passport does not bind its unsigned passport.");
  }
  if (
    !exactKeys(envelope.signature, [
      "algorithm",
      "scope",
      "devicePublicKeyPem",
      "devicePublicKeySha256",
      "value"
    ]) ||
    envelope.signature.algorithm !== RUNRAIL_DEVICE_SIGNED_REVIEW_PASSPORT.algorithm ||
    envelope.signature.scope !== RUNRAIL_DEVICE_SIGNED_REVIEW_PASSPORT.signatureScope
  ) {
    throw new TypeError("The device-signed passport signature contract is invalid.");
  }
  if (
    !exactKeys(envelope.claims, [
      "deviceKeyPossessionProven",
      "organizationalIdentityProven",
      "complianceCertificationProven",
      "codeCorrectnessProven",
      "mergeApprovalGranted"
    ]) ||
    envelope.claims.deviceKeyPossessionProven !== true ||
    Object.entries(envelope.claims)
      .filter(([key]) => key !== "deviceKeyPossessionProven")
      .some(([, value]) => value !== false)
  ) {
    throw new TypeError("The device-signed passport claims are invalid.");
  }
  if (
    !exactKeys(envelope.boundaries, [
      "pathFree",
      "sourceContentIncluded",
      "diffContentIncluded",
      "changedPathsIncluded",
      "commitIdentifiersIncluded",
      "repositoryIdentityIncluded",
      "rawVerifierOutputIncluded",
      "authority",
      "projectTestsExecuted",
      "securityReviewPerformed",
      "automaticSourceApplyEnabled",
      "learnedRuntimeAuthorityAdded"
    ]) ||
    envelope.boundaries.pathFree !== true ||
    envelope.boundaries.authority !== "none" ||
    Object.entries(envelope.boundaries)
      .filter(([key]) => !["pathFree", "authority"].includes(key))
      .some(([, value]) => value !== false)
  ) {
    throw new TypeError("The device-signed passport authority boundary is invalid.");
  }
  buildRunrailDeviceSignedReviewPassport({
    passport: envelope.passport,
    devicePublicKeyPem: envelope.signature.devicePublicKeyPem,
    devicePublicKeySha256: envelope.signature.devicePublicKeySha256,
    signature: envelope.signature.value
  });
  return envelope;
}

function exactKeys(value, keys) {
  return (
    value !== null &&
    typeof value === "object" &&
    !Array.isArray(value) &&
    Object.keys(value).sort().join("\0") === [...keys].sort().join("\0")
  );
}

function boundedInteger(value, minimum, maximum) {
  return Number.isSafeInteger(value) && value >= minimum && value <= maximum;
}

function sortedUniqueStrings(values, allowed, maximum) {
  return (
    Array.isArray(values) &&
    values.length <= maximum &&
    values.every((value) => typeof value === "string" && allowed.has(value)) &&
    new Set(values).size === values.length &&
    values.every((value, index) => index === 0 || values[index - 1] < value)
  );
}

export function buildRunrailReviewPassport(audit) {
  if (
    !audit ||
    audit.schemaVersion !== 4 ||
    audit.artifactType !== "runrail-candidate-branch-review" ||
    typeof audit.checksumSha256 !== "string" ||
    !/^[a-f0-9]{64}$/.test(audit.checksumSha256) ||
    !audit.reviewContract ||
    !Array.isArray(audit.verifier?.checks)
  ) {
    throw new TypeError("A verified Runrail schema-v4 audit is required.");
  }
  const body = {
    schemaVersion: 1,
    artifactType: "runrail-review-passport",
    product: "Runrail Local v1",
    runId: audit.runId,
    auditChecksumSha256: audit.checksumSha256,
    reviewRelationSha256: sha256(
      `runrail-review-relation-v1\0${audit.source.baseCommit}\0${audit.source.candidateCommit}`
    ),
    outcome: {
      preflightPassed: audit.preflightPassed,
      verifierPassed: audit.verifier.passed,
      reviewContractPassed: audit.reviewContract.passed,
      riskLevel: audit.decision.riskLevel,
      recommendation: audit.decision.recommendation,
      humanApprovalRequired: true,
      mergeReady: false
    },
    evidence: {
      sourceCheckoutUnchanged: audit.source.sourceCheckoutUnchanged,
      changedFileCount: audit.policy.changedFileCount,
      diffLineCount: audit.policy.diffLineCount,
      findingCounts: { ...audit.decision.findingCounts },
      verifierProfile: audit.verifier.profile,
      verifierChecks: audit.verifier.checks.map((check) => ({
        language: check.language,
        parser: check.parser,
        fileCount: check.fileCount,
        status: check.status
      })),
      reviewContractProfile: audit.reviewContract.profile,
      reviewContractSource: audit.reviewContract.source,
      reviewContractSha256: audit.reviewContract.contractSha256,
      reviewContractSourceBlobSha256: audit.reviewContract.sourceBlobSha256,
      reviewContractCandidateChanged: audit.reviewContract.candidateContractChanged,
      requiredReviewLanes: [...audit.reviewContract.requiredReviewLanes],
      requiredEvidence: [...audit.reviewContract.requiredEvidence],
      matchedRuleCount: audit.reviewContract.matchedRuleCount,
      missingCompanionGroupCount: audit.reviewContract.missingCompanionGroupCount,
      changedFileBudgetExceeded: audit.reviewContract.changedFileBudgetExceeded,
      diffLineBudgetExceeded: audit.reviewContract.diffLineBudgetExceeded
    },
    boundaries: {
      pathFree: true,
      sourceContentIncluded: false,
      diffContentIncluded: false,
      changedPathsIncluded: false,
      commitIdentifiersIncluded: false,
      repositoryIdentityIncluded: false,
      rawVerifierOutputIncluded: false,
      originAuthenticated: false,
      projectTestsExecuted: false,
      securityReviewPerformed: false,
      automaticSourceApplyEnabled: false,
      learnedRuntimeAuthorityAdded: false
    }
  };
  return { ...body, checksumSha256: sha256(stableRunrailPassportJson(body)) };
}

export function verifyRunrailReviewPassport(passport) {
  if (!exactKeys(passport, [
    "schemaVersion",
    "artifactType",
    "product",
    "runId",
    "auditChecksumSha256",
    "reviewRelationSha256",
    "outcome",
    "evidence",
    "boundaries",
    "checksumSha256"
  ])) {
    throw new TypeError("The Runrail review passport field set is invalid.");
  }
  const { checksumSha256, ...body } = passport;
  if (
    passport.schemaVersion !== 1 ||
    passport.artifactType !== "runrail-review-passport" ||
    passport.product !== "Runrail Local v1" ||
    !/^RRV-[A-F0-9]{16}-[a-f0-9]{8}$/.test(passport.runId || "") ||
    !/^[a-f0-9]{64}$/.test(passport.auditChecksumSha256 || "") ||
    !/^[a-f0-9]{64}$/.test(passport.reviewRelationSha256 || "") ||
    !/^[a-f0-9]{64}$/.test(checksumSha256 || "") ||
    checksumSha256 !== sha256(stableRunrailPassportJson(body))
  ) {
    throw new TypeError("The Runrail review passport identity or checksum is invalid.");
  }
  if (
    !exactKeys(passport.outcome, [
      "preflightPassed",
      "verifierPassed",
      "reviewContractPassed",
      "riskLevel",
      "recommendation",
      "humanApprovalRequired",
      "mergeReady"
    ]) ||
    passport.outcome.humanApprovalRequired !== true ||
    passport.outcome.mergeReady !== false
  ) {
    throw new TypeError("The Runrail review passport decision boundary is invalid.");
  }
  if (
    typeof passport.outcome.preflightPassed !== "boolean" ||
    typeof passport.outcome.verifierPassed !== "boolean" ||
    typeof passport.outcome.reviewContractPassed !== "boolean" ||
    !new Set(["low", "medium", "high"]).has(passport.outcome.riskLevel) ||
    !new Set(["manual-review", "project-tests-required", "specialist-review"]).has(
      passport.outcome.recommendation
    ) ||
    passport.outcome.preflightPassed !== (
      passport.outcome.verifierPassed &&
      passport.outcome.reviewContractPassed &&
      passport.evidence?.sourceCheckoutUnchanged === true
    )
  ) {
    throw new TypeError("The Runrail review passport outcome is invalid.");
  }
  if (
    !exactKeys(passport.evidence, [
      "sourceCheckoutUnchanged",
      "changedFileCount",
      "diffLineCount",
      "findingCounts",
      "verifierProfile",
      "verifierChecks",
      "reviewContractProfile",
      "reviewContractSource",
      "reviewContractSha256",
      "reviewContractSourceBlobSha256",
      "reviewContractCandidateChanged",
      "requiredReviewLanes",
      "requiredEvidence",
      "matchedRuleCount",
      "missingCompanionGroupCount",
      "changedFileBudgetExceeded",
      "diffLineBudgetExceeded"
    ]) ||
    passport.evidence.sourceCheckoutUnchanged !== true ||
    !boundedInteger(passport.evidence.changedFileCount, 1, 100) ||
    !boundedInteger(passport.evidence.diffLineCount, 1, 5_000) ||
    !exactKeys(passport.evidence.findingCounts, ["high", "medium", "info"]) ||
    !["high", "medium", "info"].every((key) =>
      boundedInteger(passport.evidence.findingCounts[key], 0, 20)
    ) ||
    !new Set(["safe-static", "python-compile"]).has(passport.evidence.verifierProfile) ||
    !Array.isArray(passport.evidence.verifierChecks) ||
    passport.evidence.verifierChecks.length < 1 ||
    passport.evidence.verifierChecks.length > 4 ||
    passport.evidence.reviewContractProfile !== "runrail-review-contract-v1" ||
    !new Set(["built-in", "baseline-file"]).has(passport.evidence.reviewContractSource) ||
    !/^[a-f0-9]{64}$/.test(passport.evidence.reviewContractSha256 || "") ||
    (
      passport.evidence.reviewContractSource === "built-in"
        ? passport.evidence.reviewContractSourceBlobSha256 !== null
        : !/^[a-f0-9]{64}$/.test(passport.evidence.reviewContractSourceBlobSha256 || "")
    ) ||
    typeof passport.evidence.reviewContractCandidateChanged !== "boolean" ||
    !sortedUniqueStrings(
      passport.evidence.requiredReviewLanes,
      new Set(["api", "data", "delivery", "dependency", "documentation", "policy", "product", "quality", "security"]),
      9
    ) ||
    !sortedUniqueStrings(
      passport.evidence.requiredEvidence,
      new Set([
        "api-compatibility-review",
        "data-migration-review",
        "delivery-review",
        "dependency-review",
        "documentation-review",
        "policy-owner-review",
        "product-owner-review",
        "project-tests",
        "rollback-review",
        "security-review"
      ]),
      10
    ) ||
    !boundedInteger(passport.evidence.matchedRuleCount, 0, 32) ||
    !boundedInteger(passport.evidence.missingCompanionGroupCount, 0, 128) ||
    typeof passport.evidence.changedFileBudgetExceeded !== "boolean" ||
    typeof passport.evidence.diffLineBudgetExceeded !== "boolean"
  ) {
    throw new TypeError("The Runrail review passport evidence is invalid.");
  }
  const verifierLanguages = new Set();
  let verifierFailed = false;
  for (const check of passport.evidence.verifierChecks) {
    if (
      !exactKeys(check, ["language", "parser", "fileCount", "status"]) ||
      !new Set(["python", "javascript", "json", "typescript"]).has(check.language) ||
      verifierLanguages.has(check.language) ||
      typeof check.parser !== "string" ||
      check.parser.length < 8 ||
      check.parser.length > 80 ||
      !boundedInteger(check.fileCount, 0, 2_000) ||
      !new Set(["passed", "failed", "not-applicable"]).has(check.status)
    ) {
      throw new TypeError("The Runrail review passport verifier evidence is invalid.");
    }
    verifierLanguages.add(check.language);
    verifierFailed ||= check.status === "failed";
  }
  if (
    !verifierLanguages.has("python") ||
    (
      passport.evidence.verifierProfile === "safe-static" &&
      (!verifierLanguages.has("javascript") || !verifierLanguages.has("json"))
    ) ||
    passport.outcome.verifierPassed === verifierFailed
  ) {
    throw new TypeError("The Runrail review passport verifier outcome is invalid.");
  }
  if (
    !exactKeys(passport.boundaries, [
      "pathFree",
      "sourceContentIncluded",
      "diffContentIncluded",
      "changedPathsIncluded",
      "commitIdentifiersIncluded",
      "repositoryIdentityIncluded",
      "rawVerifierOutputIncluded",
      "originAuthenticated",
      "projectTestsExecuted",
      "securityReviewPerformed",
      "automaticSourceApplyEnabled",
      "learnedRuntimeAuthorityAdded"
    ]) ||
    passport.boundaries.pathFree !== true ||
    Object.entries(passport.boundaries)
      .filter(([key]) => key !== "pathFree")
      .some(([, value]) => value !== false)
  ) {
    throw new TypeError("The Runrail review passport authority boundary is invalid.");
  }
  return passport;
}
