"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.reviewReconciliation = reviewReconciliation;
exports.acceptReconciliationArtifact = acceptReconciliationArtifact;
exports.buildReconciliationReviewArgv = buildReconciliationReviewArgv;
exports.projectReconciliationAcceptanceBody = projectReconciliationAcceptanceBody;
exports.findUniqueReconciliationSectionRange = findUniqueReconciliationSectionRange;
exports.findTextOffsets = findTextOffsets;
exports.throwAmbiguousReconciliationAcceptanceMarker = throwAmbiguousReconciliationAcceptanceMarker;
exports.throwDivergentReconciliationAcceptanceMarker = throwDivergentReconciliationAcceptanceMarker;
exports.verifyReconciliationReviewReceipt = verifyReconciliationReviewReceipt;
exports.buildReconciliationReviewReceipt = buildReconciliationReviewReceipt;
// Responsibility-focused implementation extracted from the public compatibility facade.
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const errors_1 = require("../../errors");
const mutation_preconditions_1 = require("../../filesystem/mutation-preconditions");
const repository_transaction_1 = require("../../filesystem/repository-transaction");
const canonical_write_target_1 = require("../../paths/canonical-write-target");
const front_matter_utils_1 = require("../front-matter-utils");
const contracts_1 = require("../implementation-summary/contracts");
const review_1 = require("../implementation-summary/review");
const milestone_review_1 = require("./milestone-review");
const selector_evidence_1 = require("./selector-evidence");
const task_artifact_1 = require("./task-artifact");
function reviewReconciliation(repositoryRoot, options) {
    const selector = (0, selector_evidence_1.resolveReconciliationSelector)(options);
    if (selector.kind === "task") {
        return (0, task_artifact_1.reviewTaskReconciliation)(repositoryRoot, selector.taskDefinitionPath);
    }
    return (0, milestone_review_1.reviewMilestoneReconciliation)(repositoryRoot, selector.milestoneOverviewPath);
}
function acceptReconciliationArtifact(repositoryRoot, options) {
    const currentReview = reviewReconciliation(repositoryRoot, options);
    if (currentReview.reconciliationStatus === "completed" && currentReview.artifactStatus === "completed") {
        return acceptedReconciliationReplay(repositoryRoot, options.reviewReceipt, currentReview);
    }
    verifyReconciliationReviewReceipt(options.reviewReceipt, currentReview);
    const sourcePath = currentReview.mode === "milestone"
        ? currentReview.milestoneOverviewPath
        : currentReview.taskDefinitionPath;
    const reconciliationPath = currentReview.reconciliationPath;
    const reconciliationAbsolute = node_path_1.default.join(repositoryRoot, reconciliationPath);
    const reconciliationText = node_fs_1.default.readFileSync(reconciliationAbsolute, "utf8");
    const bodyProjection = projectReconciliationAcceptanceBody(reconciliationPath, reconciliationText, currentReview.mode);
    const nextText = (0, front_matter_utils_1.applyStatusAndPlanningFieldTransition)(bodyProjection.text, {
        reconciliation_status: "completed",
        status: "completed"
    });
    if (nextText === reconciliationText) {
        throw (0, errors_1.createUsageError)(`Reconciliation '${reconciliationPath}' is already completed or acceptance would not change canonical metadata.`);
    }
    const evidencePaths = [
        sourcePath,
        reconciliationPath,
        ...options.reviewReceipt.taskSummaryRevisions.map((entry) => entry.path)
    ].filter((entry, index, entries) => entries.indexOf(entry) === index);
    const preconditions = [];
    for (const evidencePath of evidencePaths) {
        const target = {
            repositoryRelativePath: evidencePath,
            runtimePath: node_path_1.default.join(repositoryRoot, evidencePath)
        };
        preconditions.push((0, mutation_preconditions_1.captureDestinationPresencePreconditionSync)(target));
        preconditions.push((0, mutation_preconditions_1.captureContentRevisionPreconditionSync)(target));
    }
    const resultBase = {
        mode: currentReview.mode,
        sourcePath,
        reconciliationPath,
        idempotent: false,
        reviewReceiptId: options.reviewReceipt.reviewReceiptId,
        reviewReceiptProtocolVersion: options.reviewReceipt.schemaVersion,
        sourceRevision: options.reviewReceipt.sourceRevision,
        reconciliationRevision: (0, review_1.sha256ReviewSubject)(reconciliationText),
        postAcceptanceRevision: (0, review_1.sha256ReviewSubject)(nextText),
        metadataChanges: [
            { field: "reconciliation_status", from: "ready_for_review", to: "completed" },
            { field: "status", from: "active", to: "completed" }
        ],
        bodyChanges: bodyProjection.changes,
        reviewCommand: {
            command: "reconciliation review",
            argv: buildReconciliationReviewArgv(currentReview.mode, sourcePath),
            readOnly: true
        },
        intendedPaths: [reconciliationPath],
        expected: preconditions.map(mutation_preconditions_1.serializeMutationPrecondition)
    };
    if (options.dryRun === true) {
        return {
            ...resultBase,
            changedPaths: [],
            writeOutcome: "previewed",
            transactionId: null,
            conflicts: [],
            failure: null
        };
    }
    const transaction = (0, repository_transaction_1.executeRepositoryTransactionSync)(repositoryRoot, {
        writes: [{
                path: reconciliationPath,
                contents: nextText
            }],
        preconditions
    });
    return {
        ...resultBase,
        changedPaths: transaction.entries
            .slice(0, transaction.canonicalWrites)
            .map((entry) => entry.path),
        writeOutcome: transaction.outcome,
        transactionId: transaction.transactionId,
        conflicts: transaction.conflicts,
        failure: transaction.failure ?? (transaction.cleanupErrors.length > 0
            ? transaction.cleanupErrors.join(" ")
            : null)
    };
}
function acceptedReconciliationReplay(repositoryRoot, supplied, currentReview) {
    requireReconciliationReviewReceiptShape(supplied);
    const sourcePath = currentReview.mode === "milestone"
        ? currentReview.milestoneOverviewPath
        : currentReview.taskDefinitionPath;
    const reviewArgv = buildReconciliationReviewArgv(currentReview.mode, sourcePath);
    if (currentReview.closureEvidenceStatus !== "sufficient" || currentReview.blockingIssues.length > 0) {
        throw (0, errors_1.createUsageError)(`Reconciliation '${currentReview.reconciliationPath}' has terminal metadata but its current completion evidence is not sufficient; no write was applied.`, [`Run ${reviewArgv.join(" ")} and resolve the reported blockers before relying on terminal reconciliation evidence.`]);
    }
    if (supplied.mode !== currentReview.mode
        || supplied.sourcePath !== sourcePath
        || supplied.reconciliationPath !== currentReview.reconciliationPath) {
        throw staleReconciliationReviewReceipt();
    }
    const sourceRevision = (0, review_1.sha256ReviewSubject)(node_fs_1.default.readFileSync(node_path_1.default.join(repositoryRoot, sourcePath), "utf8"));
    if (supplied.sourceRevision !== sourceRevision)
        throw staleReconciliationReviewReceipt();
    for (const summary of supplied.taskSummaryRevisions) {
        let summaryTarget;
        try {
            summaryTarget = (0, canonical_write_target_1.resolveCanonicalWriteTargetSync)(repositoryRoot, summary.path);
        }
        catch {
            throw staleReconciliationReviewReceipt();
        }
        if (!summaryTarget.exists
            || (0, review_1.sha256ReviewSubject)(node_fs_1.default.readFileSync(summaryTarget.runtimePath, "utf8")) !== summary.revision) {
            throw staleReconciliationReviewReceipt();
        }
    }
    const reconciliationText = node_fs_1.default.readFileSync(node_path_1.default.join(repositoryRoot, currentReview.reconciliationPath), "utf8");
    const reviewReadyText = projectAcceptedReconciliationToReviewReady(currentReview.reconciliationPath, reconciliationText, currentReview.mode);
    const reviewReadyRevisions = new Set([
        (0, review_1.sha256ReviewSubject)(reviewReadyText),
        (0, review_1.sha256ReviewSubject)(reviewReadyText.replace(/\n/gu, "\r\n"))
    ]);
    if (!reviewReadyRevisions.has(supplied.reconciliationRevision)) {
        throw staleReconciliationReviewReceipt();
    }
    const reconciliationRevision = (0, review_1.sha256ReviewSubject)(reconciliationText);
    return {
        mode: currentReview.mode,
        sourcePath,
        reconciliationPath: currentReview.reconciliationPath,
        idempotent: true,
        reviewReceiptId: supplied.reviewReceiptId,
        reviewReceiptProtocolVersion: supplied.schemaVersion,
        sourceRevision,
        reconciliationRevision,
        postAcceptanceRevision: reconciliationRevision,
        metadataChanges: [],
        bodyChanges: [],
        reviewCommand: {
            command: "reconciliation review",
            argv: reviewArgv,
            readOnly: true
        },
        intendedPaths: [],
        changedPaths: [],
        expected: [],
        writeOutcome: "no-write",
        transactionId: null,
        conflicts: [],
        failure: null
    };
}
function projectAcceptedReconciliationToReviewReady(reconciliationPath, reconciliationText, mode) {
    const marker = mode === "milestone"
        ? {
            section: "Review Status",
            accepted: contracts_1.MILESTONE_REVIEW_ACCEPTED_MARKER,
            pending: contracts_1.MILESTONE_REVIEW_READY_MARKER,
            wholeSection: true
        }
        : {
            section: "Review Status",
            accepted: contracts_1.TASK_RECONCILIATION_ACCEPTED_MARKER,
            pending: contracts_1.TASK_RECONCILIATION_REVIEW_MARKER,
            wholeSection: false
        };
    try {
        const range = findUniqueReconciliationSectionRange(reconciliationPath, reconciliationText, {
            section: marker.section,
            from: marker.pending,
            to: marker.accepted
        });
        const content = reconciliationText.slice(range.start, range.end);
        const trimmedContent = content.trim();
        let reviewReadyBody;
        if (marker.wholeSection) {
            if (trimmedContent !== marker.accepted)
                throw new TypeError("Terminal acceptance marker is not canonical.");
            const markerOffset = content.indexOf(trimmedContent);
            reviewReadyBody = `${reconciliationText.slice(0, range.start + markerOffset)}${marker.pending}${reconciliationText.slice(range.start + markerOffset + trimmedContent.length)}`;
        }
        else {
            const acceptedOffsets = findTextOffsets(content, marker.accepted);
            if (acceptedOffsets.length !== 1)
                throw new TypeError("Terminal acceptance marker is not canonical.");
            const markerOffset = acceptedOffsets[0];
            reviewReadyBody = `${reconciliationText.slice(0, range.start + markerOffset)}${marker.pending}${reconciliationText.slice(range.start + markerOffset + marker.accepted.length)}`;
        }
        return (0, front_matter_utils_1.applyStatusAndPlanningFieldTransition)(reviewReadyBody, {
            reconciliation_status: "ready_for_review",
            status: "active"
        });
    }
    catch {
        throw staleReconciliationReviewReceipt();
    }
}
function buildReconciliationReviewArgv(mode, sourcePath) {
    return [
        "day-shift",
        "--format",
        "json",
        "reconciliation",
        "review",
        mode === "milestone" ? "--milestone-overview" : "--task-definition",
        sourcePath
    ];
}
function projectReconciliationAcceptanceBody(reconciliationPath, reconciliationText, mode) {
    const markers = [mode === "milestone"
            ? {
                section: "Review Status",
                from: contracts_1.MILESTONE_REVIEW_READY_MARKER,
                to: contracts_1.MILESTONE_REVIEW_ACCEPTED_MARKER,
                wholeSection: true
            }
            : {
                section: "Review Status",
                from: contracts_1.TASK_RECONCILIATION_REVIEW_MARKER,
                to: contracts_1.TASK_RECONCILIATION_ACCEPTED_MARKER,
                wholeSection: false
            }];
    let text = reconciliationText;
    for (const marker of markers) {
        const range = findUniqueReconciliationSectionRange(reconciliationPath, text, marker);
        const content = text.slice(range.start, range.end);
        const trimmedContent = content.trim();
        const pendingOffsets = findTextOffsets(content, marker.from);
        if (pendingOffsets.length > 1) {
            throwAmbiguousReconciliationAcceptanceMarker(reconciliationPath, marker);
        }
        if (marker.wholeSection) {
            if (trimmedContent !== marker.from) {
                throwDivergentReconciliationAcceptanceMarker(reconciliationPath, marker, trimmedContent);
            }
            const markerOffset = content.indexOf(trimmedContent);
            text = `${text.slice(0, range.start + markerOffset)}${marker.to}${text.slice(range.start + markerOffset + trimmedContent.length)}`;
            continue;
        }
        if (pendingOffsets.length !== 1) {
            throwDivergentReconciliationAcceptanceMarker(reconciliationPath, marker, trimmedContent);
        }
        const markerOffset = pendingOffsets[0];
        text = `${text.slice(0, range.start + markerOffset)}${marker.to}${text.slice(range.start + markerOffset + marker.from.length)}`;
    }
    return {
        text,
        changes: markers.map(({ section, from, to }) => ({ section, from, to }))
    };
}
function findUniqueReconciliationSectionRange(reconciliationPath, text, marker) {
    const headings = [];
    const pattern = /^##[ \t]+([^\r\n]+?)[ \t]*\r?$/gm;
    for (let match = pattern.exec(text); match !== null; match = pattern.exec(text)) {
        headings.push({
            name: match[1].trim(),
            start: match.index,
            contentStart: match.index + match[0].length
        });
    }
    const matches = headings
        .map((heading, index) => ({
        ...heading,
        end: headings[index + 1]?.start ?? text.length
    }))
        .filter((heading) => heading.name === marker.section);
    if (matches.length !== 1) {
        throwAmbiguousReconciliationAcceptanceMarker(reconciliationPath, marker);
    }
    return { start: matches[0].contentStart, end: matches[0].end };
}
function findTextOffsets(text, expected) {
    const offsets = [];
    let offset = text.indexOf(expected);
    while (offset !== -1) {
        offsets.push(offset);
        offset = text.indexOf(expected, offset + expected.length);
    }
    return offsets;
}
function throwAmbiguousReconciliationAcceptanceMarker(reconciliationPath, marker) {
    throw (0, errors_1.createUsageError)(`Reconciliation '${reconciliationPath}' has an ambiguous command-owned '${marker.section}' acceptance marker; no write was applied.`, [
        `Restore exactly one '## ${marker.section}' section containing the canonical pending marker ${JSON.stringify(marker.from)}.`,
        "Rerun reconciliation review and supply its complete current JSON result before retrying reconciliation accept."
    ]);
}
function throwDivergentReconciliationAcceptanceMarker(reconciliationPath, marker, observed) {
    const terminalWording = observed.includes(marker.to)
        ? "already contains terminal acceptance wording that is not justified by the supplied pending-state receipt"
        : "diverges from the exact command-owned pending review marker";
    throw (0, errors_1.createUsageError)(`Reconciliation '${reconciliationPath}' ${terminalWording} in '${marker.section}'; no write was applied.`, [
        `Restore the canonical pending marker ${JSON.stringify(marker.from)} without changing authored evidence in other sections.`,
        "Rerun reconciliation review and supply its complete current JSON result before retrying reconciliation accept."
    ]);
}
function verifyReconciliationReviewReceipt(supplied, currentReview) {
    requireReconciliationReviewReceiptShape(supplied);
    if (currentReview.reviewReceipt === null
        || (0, review_1.canonicalReviewJson)(currentReview.reviewReceipt) !== (0, review_1.canonicalReviewJson)(supplied)) {
        throw staleReconciliationReviewReceipt();
    }
}
function requireReconciliationReviewReceiptShape(supplied) {
    if (supplied !== null
        && typeof supplied === "object"
        && !Array.isArray(supplied)
        && typeof supplied.blockerCount === "number"
        && supplied.blockerCount !== 0) {
        throw (0, errors_1.createUsageError)(`Reconciliation acceptance cannot use a review receipt with blockerCount ${supplied.blockerCount}; no write was applied.`, [
            "Resolve every reconciliation review blocker, rerun reconciliation review, and supply its complete current zero-blocker JSON result."
        ]);
    }
    const shapeIsValid = supplied !== null
        && typeof supplied === "object"
        && !Array.isArray(supplied)
        && supplied.schemaVersion === contracts_1.RECONCILIATION_REVIEW_RECEIPT_PROTOCOL_VERSION
        && /^reconciliation-review-[a-f0-9]{24}$/.test(supplied.reviewReceiptId)
        && (supplied.mode === "milestone" || supplied.mode === "task")
        && typeof supplied.sourcePath === "string"
        && /^[a-f0-9]{64}$/.test(supplied.sourceRevision)
        && typeof supplied.reconciliationPath === "string"
        && /^[a-f0-9]{64}$/.test(supplied.reconciliationRevision)
        && supplied.reconciliationStatus === "ready_for_review"
        && supplied.artifactStatus === "active"
        && supplied.blockerCount === 0
        && Array.isArray(supplied.taskSummaryRevisions)
        && supplied.taskSummaryRevisions.every((entry) => entry !== null
            && typeof entry === "object"
            && !Array.isArray(entry)
            && typeof entry.path === "string"
            && /^[a-f0-9]{64}$/.test(entry.revision))
        && Array.isArray(supplied.authorizes)
        && supplied.authorizes.length === 1
        && supplied.authorizes[0] === "accept";
    if (!shapeIsValid) {
        throw (0, errors_1.createUsageError)("Reconciliation acceptance requires a complete zero-blocker review receipt that authorizes accept.", ["Rerun reconciliation review and supply its complete current JSON result without editing the receipt."]);
    }
    const subject = {
        schemaVersion: supplied.schemaVersion,
        mode: supplied.mode,
        sourcePath: supplied.sourcePath,
        sourceRevision: supplied.sourceRevision,
        reconciliationPath: supplied.reconciliationPath,
        reconciliationRevision: supplied.reconciliationRevision,
        taskSummaryRevisions: supplied.taskSummaryRevisions,
        reconciliationStatus: supplied.reconciliationStatus,
        artifactStatus: supplied.artifactStatus,
        blockerCount: supplied.blockerCount,
        authorizes: supplied.authorizes
    };
    const expectedId = `reconciliation-review-${(0, review_1.sha256ReviewSubject)((0, review_1.canonicalReviewJson)(subject)).slice(0, 24)}`;
    if (supplied.reviewReceiptId !== expectedId)
        throw staleReconciliationReviewReceipt();
}
function staleReconciliationReviewReceipt() {
    return (0, errors_1.createUsageError)("The reconciliation review receipt is stale, mismatched, or does not reproduce from current milestone, task-summary, and reconciliation evidence.", ["Rerun reconciliation review and supply its complete current JSON result."]);
}
function buildReconciliationReviewReceipt(repositoryRoot, options) {
    const sourceAbsolute = node_path_1.default.join(repositoryRoot, options.sourcePath);
    if (!node_fs_1.default.existsSync(sourceAbsolute)) {
        throw (0, errors_1.createUsageError)(`Reconciliation review source not found at '${options.sourcePath}'.`);
    }
    const taskSummaryRevisions = [...options.taskSummaryPaths]
        .sort((left, right) => left.localeCompare(right))
        .map((summaryPath) => {
        const summaryAbsolute = node_path_1.default.join(repositoryRoot, summaryPath);
        if (!node_fs_1.default.existsSync(summaryAbsolute)) {
            throw (0, errors_1.createUsageError)(`Reconciliation task-summary evidence not found at '${summaryPath}'.`);
        }
        return {
            path: summaryPath,
            revision: (0, review_1.sha256ReviewSubject)(node_fs_1.default.readFileSync(summaryAbsolute, "utf8"))
        };
    });
    const subject = {
        schemaVersion: contracts_1.RECONCILIATION_REVIEW_RECEIPT_PROTOCOL_VERSION,
        mode: options.mode,
        sourcePath: options.sourcePath,
        sourceRevision: (0, review_1.sha256ReviewSubject)(node_fs_1.default.readFileSync(sourceAbsolute, "utf8")),
        reconciliationPath: options.reconciliationPath,
        reconciliationRevision: (0, review_1.sha256ReviewSubject)(options.reconciliationText),
        taskSummaryRevisions,
        reconciliationStatus: "ready_for_review",
        artifactStatus: "active",
        blockerCount: 0,
        authorizes: ["accept"]
    };
    return {
        ...subject,
        reviewReceiptId: `reconciliation-review-${(0, review_1.sha256ReviewSubject)((0, review_1.canonicalReviewJson)(subject)).slice(0, 24)}`
    };
}
