import { createHash } from "node:crypto";
import {
  lstat,
  mkdir,
  readFile,
  readdir,
  realpath,
  rm,
  writeFile
} from "node:fs/promises";
import path from "node:path";
import { verifyRunrailCandidateAudit } from "./runrail-deepseek-advisory-core.mjs";
import { LocalAuditRunnerError } from "./veyact-local-audit-runner-core.mjs";

export const RUNRAIL_HUNK_CONTINUITY = Object.freeze({
  schemaVersion: 1,
  artifactType: "runrail-hunk-continuity",
  profile: "runrail-hunk-continuity-v1",
  product: "Runrail Local v1"
});

const ATTENTION_ARTIFACT_TYPE = "runrail-hunk-attention";
const allowedStatuses = new Set(["unreviewed", "reviewed", "needs-revision"]);
const SHA256_PATTERN = /^[a-f0-9]{64}$/;
const HUNK_ID_PATTERN = /^HNK-[A-F0-9]{24}$/;
const COVERAGE_ID_PATTERN = /^COV-[A-F0-9]{24}$/;
const MAX_HUNKS = 2_000;

function fail(code, message) {
  throw new LocalAuditRunnerError(code, message);
}

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;
}

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

function exactObject(value, keys, label) {
  if (!value || typeof value !== "object" || Array.isArray(value)) {
    fail("hunk-continuity-schema-invalid", `${label} must be an object.`);
  }
  const actual = Object.keys(value).sort();
  const expected = [...keys].sort();
  if (
    actual.length !== expected.length ||
    actual.some((key, index) => key !== expected[index])
  ) {
    fail(
      "hunk-continuity-schema-invalid",
      `${label} contains missing or unsupported fields.`
    );
  }
}

function exactArray(value, label, maximum = MAX_HUNKS) {
  if (!Array.isArray(value) || value.length > maximum) {
    fail(
      "hunk-continuity-schema-invalid",
      `${label} must be an array with no more than ${maximum} entries.`
    );
  }
}

function isInside(candidate, root) {
  const relative = path.relative(root, candidate);
  return (
    relative !== "" &&
    relative !== ".." &&
    !relative.startsWith(`..${path.sep}`) &&
    !path.isAbsolute(relative)
  );
}

export function parseRunrailPatchHunks(
  patchText,
  { sourceAuditChecksumSha256, diffSha256 } = {}
) {
  if (
    typeof patchText !== "string" ||
    !SHA256_PATTERN.test(String(sourceAuditChecksumSha256 || "")) ||
    !SHA256_PATTERN.test(String(diffSha256 || "")) ||
    sha256(patchText) !== diffSha256
  ) {
    fail(
      "hunk-continuity-patch-invalid",
      "Review Coverage requires the exact checksum-bound Runrail candidate patch."
    );
  }
  const lines = (patchText.endsWith("\n") ? patchText.slice(0, -1) : patchText).split("\n");
  const parsed = [];
  let fileScopeSha256 = "";
  for (let index = 0; index < lines.length; index += 1) {
    const line = lines[index];
    if (line.startsWith("diff --git ")) {
      fileScopeSha256 = sha256(`runrail-file-scope-v1\0${line}`);
      continue;
    }
    if (!line.startsWith("@@ ")) continue;
    if (!fileScopeSha256) {
      fail(
        "hunk-continuity-patch-invalid",
        "The Runrail candidate patch contains a hunk without a file scope."
      );
    }
    const hunkLines = [line];
    for (let cursor = index + 1; cursor < lines.length; cursor += 1) {
      const next = lines[cursor];
      if (next.startsWith("diff --git ") || next.startsWith("@@ ")) break;
      hunkLines.push(next);
      index = cursor;
    }
    const body = hunkLines.slice(1);
    const continuitySha256 = sha256(
      `runrail-hunk-continuity-v1\0${fileScopeSha256}\0${hunkLines.join("\n")}`
    );
    parsed.push({
      continuitySha256,
      addedLineCount: body.filter((value) => value.startsWith("+")).length,
      removedLineCount: body.filter((value) => value.startsWith("-")).length,
      contextLineCount: body.filter(
        (value) => value.startsWith(" ") || value.startsWith("\\ No newline")
      ).length
    });
    if (parsed.length > MAX_HUNKS) {
      fail(
        "hunk-continuity-size-boundary",
        `Review Coverage accepts at most ${MAX_HUNKS} diff hunks.`
      );
    }
  }

  const occurrenceByContinuity = new Map();
  return parsed.map((hunk) => {
    const occurrence = (occurrenceByContinuity.get(hunk.continuitySha256) || 0) + 1;
    occurrenceByContinuity.set(hunk.continuitySha256, occurrence);
    return Object.freeze({
      hunkId: `HNK-${sha256(
        `runrail-hunk-id-v1\0${sourceAuditChecksumSha256}\0${hunk.continuitySha256}\0${occurrence}`
      )
        .slice(0, 24)
        .toUpperCase()}`,
      ...hunk
    });
  });
}

export function stableRunrailHunkAttentionJson(attention) {
  return stableJson(attention);
}

export function buildRunrailHunkAttentionManifest(coverage, states) {
  verifyRunrailHunkContinuity(coverage);
  exactArray(states, "Review Coverage attention states");
  const knownHunks = new Set(coverage.hunks.map((hunk) => hunk.hunkId));
  const seen = new Set();
  const normalizedStates = states
    .map((state) => {
      exactObject(state, ["hunkId", "status"], "Review Coverage attention state");
      if (
        !HUNK_ID_PATTERN.test(String(state.hunkId || "")) ||
        !knownHunks.has(state.hunkId) ||
        !allowedStatuses.has(state.status) ||
        seen.has(state.hunkId)
      ) {
        fail(
          "hunk-attention-invalid",
          "Review Coverage attention must reference each current hunk at most once with a supported status."
        );
      }
      seen.add(state.hunkId);
      return { hunkId: state.hunkId, status: state.status };
    })
    .sort((left, right) => left.hunkId.localeCompare(right.hunkId));
  const body = {
    schemaVersion: 1,
    artifactType: ATTENTION_ARTIFACT_TYPE,
    sourceAuditChecksumSha256: coverage.source.auditChecksumSha256,
    states: normalizedStates,
    authority: "none"
  };
  return Object.freeze({
    ...body,
    checksumSha256: sha256(stableJson(body))
  });
}

export function verifyRunrailHunkAttentionManifest(attention, coverage = null) {
  exactObject(
    attention,
    [
      "schemaVersion",
      "artifactType",
      "sourceAuditChecksumSha256",
      "states",
      "authority",
      "checksumSha256"
    ],
    "Review Coverage attention manifest"
  );
  if (
    attention.schemaVersion !== 1 ||
    attention.artifactType !== ATTENTION_ARTIFACT_TYPE ||
    attention.authority !== "none" ||
    !SHA256_PATTERN.test(String(attention.sourceAuditChecksumSha256 || ""))
  ) {
    fail("hunk-attention-invalid", "The Review Coverage attention contract is invalid.");
  }
  const { checksumSha256, ...body } = attention;
  if (
    !SHA256_PATTERN.test(String(checksumSha256 || "")) ||
    sha256(stableJson(body)) !== checksumSha256
  ) {
    fail("hunk-attention-invalid", "The Review Coverage attention checksum is invalid.");
  }
  exactArray(attention.states, "Review Coverage attention states");
  const knownHunks = coverage
    ? new Set(coverage.hunks.map((hunk) => hunk.hunkId))
    : null;
  const seen = new Set();
  for (const state of attention.states) {
    exactObject(state, ["hunkId", "status"], "Review Coverage attention state");
    if (
      !HUNK_ID_PATTERN.test(String(state.hunkId || "")) ||
      !allowedStatuses.has(state.status) ||
      seen.has(state.hunkId) ||
      (knownHunks && !knownHunks.has(state.hunkId))
    ) {
      fail("hunk-attention-invalid", "The Review Coverage attention state is invalid.");
    }
    seen.add(state.hunkId);
  }
  if (
    coverage &&
    attention.sourceAuditChecksumSha256 !== coverage.source.auditChecksumSha256
  ) {
    fail(
      "hunk-attention-stale",
      "The Review Coverage attention manifest belongs to a different review."
    );
  }
  return attention;
}

function countByContinuity(hunks) {
  const counts = new Map();
  for (const hunk of hunks) {
    counts.set(
      hunk.continuitySha256,
      (counts.get(hunk.continuitySha256) || 0) + 1
    );
  }
  return counts;
}

export function buildRunrailHunkContinuity({
  audit,
  patchText,
  attention = null,
  previousCoverage = null
}) {
  verifyRunrailCandidateAudit(audit);
  const parsedHunks = parseRunrailPatchHunks(patchText, {
    sourceAuditChecksumSha256: audit.checksumSha256,
    diffSha256: audit.policy.diffSha256
  });
  if (previousCoverage) verifyRunrailHunkContinuity(previousCoverage);
  const baseCommitBindingSha256 = sha256(
    `runrail-base-commit-binding-v1\0${audit.source.baseCommit}`
  );
  const candidateCommitBindingSha256 = sha256(
    `runrail-candidate-commit-binding-v1\0${audit.source.candidateCommit}`
  );
  if (
    previousCoverage &&
    previousCoverage.source.baseCommitBindingSha256 !== baseCommitBindingSha256 &&
    previousCoverage.source.candidateCommitBindingSha256 !== baseCommitBindingSha256
  ) {
    fail(
      "hunk-continuity-unrelated",
      "Review Coverage may carry attention only across reviews with a bound revision relationship."
    );
  }
  const provisional = {
    source: { auditChecksumSha256: audit.checksumSha256 },
    hunks: parsedHunks
  };
  if (attention) verifyRunrailHunkAttentionManifest(attention, provisional);

  const currentContinuityCounts = countByContinuity(parsedHunks);
  const previousContinuityCounts = previousCoverage
    ? countByContinuity(previousCoverage.hunks)
    : new Map();
  const previousByContinuity = new Map(
    (previousCoverage?.hunks || []).map((hunk) => [hunk.continuitySha256, hunk])
  );
  const explicitStatuses = new Map(
    (attention?.states || []).map((state) => [state.hunkId, state.status])
  );
  const hunks = parsedHunks.map((hunk) => {
    const previous = previousByContinuity.get(hunk.continuitySha256);
    const mayCarry = Boolean(
      previous &&
      previous.status !== "unreviewed" &&
      currentContinuityCounts.get(hunk.continuitySha256) === 1 &&
      previousContinuityCounts.get(hunk.continuitySha256) === 1
    );
    const carriedStatus = mayCarry ? previous.status : "unreviewed";
    const status = explicitStatuses.get(hunk.hunkId) || carriedStatus;
    return {
      ...hunk,
      status,
      carriedFromPrevious: mayCarry && !explicitStatuses.has(hunk.hunkId)
    };
  });
  const summary = {
    hunkCount: hunks.length,
    reviewedCount: hunks.filter((hunk) => hunk.status === "reviewed").length,
    needsRevisionCount: hunks.filter((hunk) => hunk.status === "needs-revision").length,
    unreviewedCount: hunks.filter((hunk) => hunk.status === "unreviewed").length,
    carriedForwardCount: hunks.filter((hunk) => hunk.carriedFromPrevious).length,
    attentionComplete: hunks.length > 0 && hunks.every((hunk) => hunk.status !== "unreviewed")
  };
  const previousChecksumSha256 = previousCoverage?.checksumSha256 || null;
  const attentionChecksumSha256 = attention?.checksumSha256 || null;
  const identity = sha256(
    stableJson({
      auditChecksumSha256: audit.checksumSha256,
      previousChecksumSha256,
      attentionChecksumSha256,
      hunks
    })
  );
  const body = {
    ...RUNRAIL_HUNK_CONTINUITY,
    coverageId: `COV-${identity.slice(0, 24).toUpperCase()}`,
    source: {
      auditChecksumSha256: audit.checksumSha256,
      diffSha256: audit.policy.diffSha256,
      changedFileCount: audit.policy.changedFileCount,
      baseCommitBindingSha256,
      candidateCommitBindingSha256
    },
    provenance: {
      previousCoverageChecksumSha256: previousChecksumSha256,
      attentionManifestChecksumSha256: attentionChecksumSha256
    },
    summary,
    hunks,
    boundaries: {
      pathFree: true,
      authority: "none",
      humanAttentionNotApproval: true,
      mergeReady: false,
      projectTestsExecuted: false,
      networkUsed: false,
      repositoryOpened: false,
      sourceMutation: false,
      originAuthenticated: false
    }
  };
  return Object.freeze({
    ...body,
    checksumSha256: sha256(stableJson(body))
  });
}

export function stableRunrailHunkContinuityJson(coverage) {
  verifyRunrailHunkContinuity(coverage);
  return stableJson(coverage);
}

export function verifyRunrailHunkContinuity(coverage) {
  exactObject(
    coverage,
    [
      "schemaVersion",
      "artifactType",
      "profile",
      "product",
      "coverageId",
      "source",
      "provenance",
      "summary",
      "hunks",
      "boundaries",
      "checksumSha256"
    ],
    "Review Coverage artifact"
  );
  if (
    coverage.schemaVersion !== RUNRAIL_HUNK_CONTINUITY.schemaVersion ||
    coverage.artifactType !== RUNRAIL_HUNK_CONTINUITY.artifactType ||
    coverage.profile !== RUNRAIL_HUNK_CONTINUITY.profile ||
    coverage.product !== RUNRAIL_HUNK_CONTINUITY.product ||
    !COVERAGE_ID_PATTERN.test(String(coverage.coverageId || ""))
  ) {
    fail("hunk-continuity-invalid", "The Review Coverage artifact identity is invalid.");
  }
  exactObject(
    coverage.source,
    [
      "auditChecksumSha256",
      "diffSha256",
      "changedFileCount",
      "baseCommitBindingSha256",
      "candidateCommitBindingSha256"
    ],
    "Review Coverage source"
  );
  exactObject(
    coverage.provenance,
    ["previousCoverageChecksumSha256", "attentionManifestChecksumSha256"],
    "Review Coverage provenance"
  );
  exactObject(
    coverage.summary,
    [
      "hunkCount",
      "reviewedCount",
      "needsRevisionCount",
      "unreviewedCount",
      "carriedForwardCount",
      "attentionComplete"
    ],
    "Review Coverage summary"
  );
  exactObject(
    coverage.boundaries,
    [
      "pathFree",
      "authority",
      "humanAttentionNotApproval",
      "mergeReady",
      "projectTestsExecuted",
      "networkUsed",
      "repositoryOpened",
      "sourceMutation",
      "originAuthenticated"
    ],
    "Review Coverage boundaries"
  );
  exactArray(coverage.hunks, "Review Coverage hunks");
  if (
    !SHA256_PATTERN.test(String(coverage.source.auditChecksumSha256 || "")) ||
    !SHA256_PATTERN.test(String(coverage.source.diffSha256 || "")) ||
    !SHA256_PATTERN.test(String(coverage.source.baseCommitBindingSha256 || "")) ||
    !SHA256_PATTERN.test(String(coverage.source.candidateCommitBindingSha256 || "")) ||
    !Number.isSafeInteger(coverage.source.changedFileCount) ||
    coverage.source.changedFileCount < 0 ||
    ![null, undefined].includes(coverage.provenance.previousCoverageChecksumSha256) &&
      !SHA256_PATTERN.test(String(coverage.provenance.previousCoverageChecksumSha256)) ||
    ![null, undefined].includes(coverage.provenance.attentionManifestChecksumSha256) &&
      !SHA256_PATTERN.test(String(coverage.provenance.attentionManifestChecksumSha256))
  ) {
    fail("hunk-continuity-invalid", "The Review Coverage source or provenance is invalid.");
  }
  const seenHunks = new Set();
  for (const hunk of coverage.hunks) {
    exactObject(
      hunk,
      [
        "hunkId",
        "continuitySha256",
        "addedLineCount",
        "removedLineCount",
        "contextLineCount",
        "status",
        "carriedFromPrevious"
      ],
      "Review Coverage hunk"
    );
    if (
      !HUNK_ID_PATTERN.test(String(hunk.hunkId || "")) ||
      !SHA256_PATTERN.test(String(hunk.continuitySha256 || "")) ||
      !allowedStatuses.has(hunk.status) ||
      typeof hunk.carriedFromPrevious !== "boolean" ||
      seenHunks.has(hunk.hunkId) ||
      !["addedLineCount", "removedLineCount", "contextLineCount"].every(
        (key) => Number.isSafeInteger(hunk[key]) && hunk[key] >= 0
      )
    ) {
      fail("hunk-continuity-invalid", "A Review Coverage hunk is invalid.");
    }
    seenHunks.add(hunk.hunkId);
  }
  const expectedSummary = {
    hunkCount: coverage.hunks.length,
    reviewedCount: coverage.hunks.filter((hunk) => hunk.status === "reviewed").length,
    needsRevisionCount: coverage.hunks.filter(
      (hunk) => hunk.status === "needs-revision"
    ).length,
    unreviewedCount: coverage.hunks.filter((hunk) => hunk.status === "unreviewed").length,
    carriedForwardCount: coverage.hunks.filter((hunk) => hunk.carriedFromPrevious).length,
    attentionComplete:
      coverage.hunks.length > 0 &&
      coverage.hunks.every((hunk) => hunk.status !== "unreviewed")
  };
  if (stableJson(expectedSummary) !== stableJson(coverage.summary)) {
    fail("hunk-continuity-invalid", "The Review Coverage summary does not match its hunks.");
  }
  if (
    coverage.boundaries.pathFree !== true ||
    coverage.boundaries.authority !== "none" ||
    coverage.boundaries.humanAttentionNotApproval !== true ||
    coverage.boundaries.mergeReady !== false ||
    coverage.boundaries.projectTestsExecuted !== false ||
    coverage.boundaries.networkUsed !== false ||
    coverage.boundaries.repositoryOpened !== false ||
    coverage.boundaries.sourceMutation !== false ||
    coverage.boundaries.originAuthenticated !== false
  ) {
    fail("hunk-continuity-authority", "Review Coverage expanded its evidence boundary.");
  }
  const { checksumSha256, ...body } = coverage;
  if (
    !SHA256_PATTERN.test(String(checksumSha256 || "")) ||
    sha256(stableJson(body)) !== checksumSha256
  ) {
    fail("hunk-continuity-checksum", "The Review Coverage checksum is invalid.");
  }
  return coverage;
}

export function renderRunrailHunkContinuityMarkdown(coverage) {
  verifyRunrailHunkContinuity(coverage);
  const rows = coverage.hunks.length
    ? coverage.hunks
        .map(
          (hunk, index) =>
            `${index + 1}. \`${hunk.hunkId}\` - **${hunk.status}**` +
            ` (${hunk.addedLineCount} added, ${hunk.removedLineCount} removed, ` +
            `${hunk.contextLineCount} context${hunk.carriedFromPrevious ? ", carried exactly" : ""})`
        )
        .join("\n")
    : "No textual diff hunks were present.";
  return `# Runrail Review Coverage

Coverage ID: \`${coverage.coverageId}\`

- Reviewed: ${coverage.summary.reviewedCount}
- Needs revision: ${coverage.summary.needsRevisionCount}
- Unreviewed: ${coverage.summary.unreviewedCount}
- Carried from an exact prior hunk: ${coverage.summary.carriedForwardCount}

## Hunk attention

${rows}

## Decision boundary

This path-free artifact records human attention state, not approval. Changed, shifted, duplicated, split, ambiguous, or new hunks remain unreviewed. Runrail did not open a repository, execute project tests, call a provider, mutate source, authenticate origin, or approve a merge.

Checksum: \`${coverage.checksumSha256}\`
`;
}

function escapeHtml(value) {
  return String(value)
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#39;");
}

export function renderRunrailHunkContinuityHtml(coverage) {
  verifyRunrailHunkContinuity(coverage);
  const rows = coverage.hunks
    .map(
      (hunk, index) =>
        `<li><span>${index + 1}</span><div><strong>${escapeHtml(hunk.status)}</strong>` +
        `<code>${escapeHtml(hunk.hunkId)}</code><small>${hunk.addedLineCount} added · ` +
        `${hunk.removedLineCount} removed · ${hunk.contextLineCount} context` +
        `${hunk.carriedFromPrevious ? " · carried exactly" : ""}</small></div></li>`
    )
    .join("");
  return `<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'">
  <title>Runrail Review Coverage</title>
  <style>
    :root{color-scheme:light;--ink:#101820;--muted:#5c6871;--line:#d8dee1;--paper:#fff;--wash:#f3f5f4;--green:#0b6c4e;--amber:#805500;--red:#982d25}*{box-sizing:border-box}body{margin:0;background:var(--wash);color:var(--ink);font:15px/1.55 ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}main{width:min(960px,calc(100% - 32px));margin:0 auto;padding:42px 0 68px}.eyebrow{margin:0;color:var(--green);font-size:11px;font-weight:900;text-transform:uppercase}h1{margin:6px 0 9px;font-size:clamp(32px,5vw,54px);line-height:1.02}p{margin:0;color:var(--muted)}.summary{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));margin:30px 0;border:1px solid var(--line);background:var(--paper)}.summary div{padding:18px;border-right:1px solid var(--line)}.summary div:last-child{border:0}.summary span{display:block;color:var(--muted);font-size:12px}.summary strong{font-size:24px}ol{margin:0;padding:0;list-style:none;border-top:1px solid var(--line)}li{display:grid;grid-template-columns:34px minmax(0,1fr);gap:14px;padding:16px 0;border-bottom:1px solid var(--line)}li>span{display:grid;width:28px;height:28px;place-items:center;border:1px solid var(--line);font-weight:800}li strong{display:block;text-transform:capitalize}li code,li small{display:block;color:var(--muted);overflow-wrap:anywhere}.boundary{margin-top:28px;padding:22px;border:1px solid var(--line);background:var(--paper)}.checksum{margin-top:22px;font:10px/1.5 ui-monospace,SFMono-Regular,Consolas,monospace;overflow-wrap:anywhere}@media(max-width:650px){.summary{grid-template-columns:1fr 1fr}.summary div:nth-child(2){border-right:0}.summary div:nth-child(-n+2){border-bottom:1px solid var(--line)}}
  </style>
</head>
<body>
<main>
  <p class="eyebrow">Runrail local review continuity</p>
  <h1>Know which exact hunks still need attention.</h1>
  <p>${escapeHtml(coverage.coverageId)} · path-free · authority none</p>
  <section class="summary"><div><span>Reviewed</span><strong>${coverage.summary.reviewedCount}</strong></div><div><span>Needs revision</span><strong>${coverage.summary.needsRevisionCount}</strong></div><div><span>Unreviewed</span><strong>${coverage.summary.unreviewedCount}</strong></div><div><span>Carried exactly</span><strong>${coverage.summary.carriedForwardCount}</strong></div></section>
  <ol>${rows || "<li><span>0</span><div><strong>No textual hunks</strong><small>No hunk attention state was created.</small></div></li>"}</ol>
  <section class="boundary"><p class="eyebrow">Decision boundary</p><h2>Attention is not approval.</h2><p>Changed, shifted, duplicated, split, ambiguous, or new hunks reset to unreviewed. Runrail did not open a repository, execute project tests, call a provider, mutate source, authenticate origin, or approve a merge.</p></section>
  <p class="checksum">Coverage checksum: ${escapeHtml(coverage.checksumSha256)}</p>
</main>
</body>
</html>
`;
}

async function verifyStoredCoverage({
  coverage,
  coveragePath,
  reviewPath,
  htmlReportPath
}) {
  for (const artifactPath of [coveragePath, reviewPath, htmlReportPath]) {
    const entry = await lstat(artifactPath);
    if (!entry.isFile() || entry.isSymbolicLink()) {
      fail(
        "hunk-continuity-artifact-boundary",
        "Review Coverage artifacts must be ordinary Runrail-owned files."
      );
    }
  }
  const storedCoverage = JSON.parse(await readFile(coveragePath, "utf8"));
  verifyRunrailHunkContinuity(storedCoverage);
  if (
    stableRunrailHunkContinuityJson(storedCoverage) !==
      stableRunrailHunkContinuityJson(coverage) ||
    (await readFile(reviewPath, "utf8")) !==
      renderRunrailHunkContinuityMarkdown(coverage) ||
    (await readFile(htmlReportPath, "utf8")) !== renderRunrailHunkContinuityHtml(coverage)
  ) {
    fail(
      "hunk-continuity-artifact-mismatch",
      "Stored Review Coverage artifacts do not match their deterministic rebuild."
    );
  }
}

async function resolveOrdinaryReviewRoot(reviewRoot) {
  let before;
  let canonicalReviewRoot;
  let after;
  try {
    before = await lstat(reviewRoot);
    if (!before.isDirectory() || before.isSymbolicLink()) {
      fail(
        "hunk-continuity-artifact-boundary",
        "The Review Coverage parent must be an ordinary Runrail-owned review directory."
      );
    }
    canonicalReviewRoot = await realpath(reviewRoot);
    after = await lstat(reviewRoot);
  } catch (error) {
    if (error instanceof LocalAuditRunnerError) throw error;
    fail(
      "hunk-continuity-artifact-boundary",
      "The Review Coverage parent is missing or no longer accessible."
    );
  }
  if (
    !after.isDirectory() ||
    after.isSymbolicLink() ||
    String(before.dev) !== String(after.dev) ||
    String(before.ino) !== String(after.ino)
  ) {
    fail(
      "hunk-continuity-artifact-boundary",
      "The Review Coverage parent changed while its artifact boundary was being verified."
    );
  }
  return canonicalReviewRoot;
}

export async function writeRunrailHunkContinuityArtifacts({
  audit,
  patchText,
  reviewRoot,
  attention = null,
  previousCoverage = null
}) {
  const coverage = buildRunrailHunkContinuity({
    audit,
    patchText,
    attention,
    previousCoverage
  });
  const canonicalReviewRoot = await resolveOrdinaryReviewRoot(reviewRoot);
  const coverageRoot = path.join(canonicalReviewRoot, "coverage");
  try {
    const existing = await lstat(coverageRoot);
    if (!existing.isDirectory() || existing.isSymbolicLink()) {
      fail(
        "hunk-continuity-artifact-boundary",
        "The Review Coverage root must be an ordinary Runrail-owned directory."
      );
    }
    if (!isInside(await realpath(coverageRoot), canonicalReviewRoot)) {
      fail(
        "hunk-continuity-artifact-boundary",
        "The Review Coverage root escaped its Runrail review directory."
      );
    }
  } catch (error) {
    if (error instanceof LocalAuditRunnerError) throw error;
    if (error?.code !== "ENOENT") throw error;
    await mkdir(coverageRoot, { mode: 0o700 });
  }

  const outputRoot = path.join(coverageRoot, coverage.coverageId);
  let created = false;
  try {
    await mkdir(outputRoot, { mode: 0o700 });
    created = true;
  } catch (error) {
    if (error?.code !== "EEXIST") throw error;
    const entry = await lstat(outputRoot);
    if (!entry.isDirectory() || entry.isSymbolicLink()) {
      fail(
        "hunk-continuity-artifact-boundary",
        "The Review Coverage output must be an ordinary Runrail-owned directory."
      );
    }
    const entries = (await readdir(outputRoot)).sort();
    if (entries.join(",") !== "REVIEW_COVERAGE.md,coverage.html,coverage.json") {
      fail(
        "hunk-continuity-artifact-mismatch",
        "The existing Review Coverage output contains an invalid file set."
      );
    }
  }
  const canonicalOutputRoot = await realpath(outputRoot);
  if (!isInside(canonicalOutputRoot, canonicalReviewRoot)) {
    if (created) await rm(outputRoot, { recursive: true, force: true });
    fail(
      "hunk-continuity-artifact-boundary",
      "The Review Coverage output escaped its Runrail review directory."
    );
  }

  const coveragePath = path.join(outputRoot, "coverage.json");
  const reviewPath = path.join(outputRoot, "REVIEW_COVERAGE.md");
  const htmlReportPath = path.join(outputRoot, "coverage.html");
  if (created) {
    try {
      await writeFile(coveragePath, stableRunrailHunkContinuityJson(coverage), {
        encoding: "utf8",
        mode: 0o600,
        flag: "wx"
      });
      await writeFile(reviewPath, renderRunrailHunkContinuityMarkdown(coverage), {
        encoding: "utf8",
        mode: 0o600,
        flag: "wx"
      });
      await writeFile(htmlReportPath, renderRunrailHunkContinuityHtml(coverage), {
        encoding: "utf8",
        mode: 0o600,
        flag: "wx"
      });
    } catch (error) {
      await rm(outputRoot, { recursive: true, force: true }).catch(() => {});
      throw error;
    }
  }
  await verifyStoredCoverage({ coverage, coveragePath, reviewPath, htmlReportPath });
  return {
    ok: true,
    mode: "local-hunk-continuity",
    coverageId: coverage.coverageId,
    outputRoot,
    coveragePath,
    reviewPath,
    htmlReportPath,
    ...coverage.summary,
    authority: "none",
    mergeReady: false,
    projectTestsExecuted: false,
    networkUsed: false,
    sourceMutation: false,
    coverage
  };
}
