"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.syncStructuralPressureState = syncStructuralPressureState;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const errors_1 = require("../../errors");
const paths_1 = require("../../paths");
const implementation_summary_reconciliation_1 = require("../implementation-summary-reconciliation");
const planning_document_utils_1 = require("../planning-document-utils");
const contracts_1 = require("./contracts");
const delta_evidence_1 = require("./delta-evidence");
const state_1 = require("./state");
function syncStructuralPressureState(repositoryRoot, options) {
    const reconciliationPath = (0, paths_1.parseRepositoryRelativePath)(options.milestoneReconciliationPath).normalizedPath;
    const reconciliationAbsolutePath = (0, paths_1.resolveRepositoryRelativePath)(repositoryRoot, reconciliationPath);
    if (!node_fs_1.default.existsSync(reconciliationAbsolutePath)) {
        throw (0, errors_1.createUsageError)(`Milestone reconciliation not found at '${reconciliationPath}'.`, ["Pass an existing repository-relative --milestone-reconciliation path."]);
    }
    const reconciliationText = node_fs_1.default.readFileSync(reconciliationAbsolutePath, "utf8");
    const frontMatterLines = parseFrontMatterLines(reconciliationPath, reconciliationText);
    const artifactType = (0, planning_document_utils_1.readTopLevelField)(frontMatterLines, "artifact_type")?.trim() ?? null;
    if (artifactType !== "reconciliation") {
        throw (0, errors_1.createUsageError)(`Artifact '${reconciliationPath}' must use artifact_type 'reconciliation'.`, ["Pass a repository-relative milestone reconciliation artifact."]);
    }
    const milestoneOverviewPath = (0, planning_document_utils_1.readUpstreamField)(frontMatterLines, "milestone_overview")?.trim() ?? null;
    if (milestoneOverviewPath === null || milestoneOverviewPath === "") {
        throw new errors_1.RuntimeError({
            message: "Structural-pressure sync rejected because the reconciliation artifact is missing upstream milestone context.",
            code: "STRUCTURAL_PRESSURE_SYNC_REJECTED",
            exitCode: errors_1.RuntimeExitCode.ERROR,
            details: [
                `Artifact '${reconciliationPath}' must declare upstream.milestone_overview before sync can mirror derived state.`
            ]
        });
    }
    const reconciliationReview = (0, implementation_summary_reconciliation_1.reviewReconciliation)(repositoryRoot, {
        milestoneOverviewPath
    });
    if (reconciliationReview.closureEvidenceStatus !== "sufficient") {
        throw new errors_1.RuntimeError({
            message: "Structural-pressure sync rejected because milestone reconciliation evidence is incomplete or ambiguous.",
            code: "STRUCTURAL_PRESSURE_SYNC_REJECTED",
            exitCode: errors_1.RuntimeExitCode.ERROR,
            details: [
                ...reconciliationReview.evidenceGaps,
                ...reconciliationReview.placeholderResidue,
                ...reconciliationReview.alignmentIssues,
                ...reconciliationReview.reviewConcerns
            ]
        });
    }
    requireAcceptedStructuralPressureReconciliation(reconciliationText, reconciliationPath);
    const payload = extractSyncPayload(reconciliationText, reconciliationPath);
    const entries = validateSyncPayloadEntries(repositoryRoot, payload.entries, reconciliationPath, milestoneOverviewPath);
    const nextState = {
        schema_version: 1,
        synced_at: new Date().toISOString(),
        source: {
            milestone_reconciliation: reconciliationPath,
            milestone_overview: milestoneOverviewPath
        },
        entries
    };
    const rendered = `${JSON.stringify(nextState, null, 2)}\n`;
    const stateAbsolutePath = (0, paths_1.resolveRepositoryRelativePath)(repositoryRoot, contracts_1.STRUCTURAL_PRESSURE_STATE_PATH);
    const previous = node_fs_1.default.existsSync(stateAbsolutePath)
        ? (0, state_1.parseStructuralPressureState)(node_fs_1.default.readFileSync(stateAbsolutePath, "utf8"), contracts_1.STRUCTURAL_PRESSURE_STATE_PATH)
        : null;
    const changed = previous === null || structuralPressureMaterialStateChanged(previous, nextState);
    if (changed) {
        node_fs_1.default.mkdirSync(node_path_1.default.dirname(stateAbsolutePath), { recursive: true });
        node_fs_1.default.writeFileSync(stateAbsolutePath, rendered, "utf8");
    }
    return {
        reconciliationPath,
        milestoneOverviewPath,
        statePath: contracts_1.STRUCTURAL_PRESSURE_STATE_PATH,
        entryCount: entries.length,
        changed,
        writeApplied: changed
    };
}
function structuralPressureMaterialStateChanged(previous, next) {
    return JSON.stringify({
        source: previous.source,
        entries: previous.entries
    }) !== JSON.stringify({
        source: next.source,
        entries: next.entries
    });
}
function parseFrontMatterLines(filePath, text) {
    if (!text.startsWith("---\n")) {
        throw (0, errors_1.createUsageError)(`Artifact '${filePath}' is missing required YAML front matter.`, ["Repair the reconciliation artifact before running sync."]);
    }
    const endIndex = text.indexOf("\n---\n");
    if (endIndex < 0) {
        throw (0, errors_1.createUsageError)(`Artifact '${filePath}' has malformed YAML front matter.`, ["Repair the reconciliation artifact before running sync."]);
    }
    return text
        .slice(4, endIndex)
        .split(/\r?\n/);
}
function extractSyncPayload(reconciliationText, reconciliationPath) {
    const fencePattern = new RegExp(`\`\`\`${contracts_1.STRUCTURAL_PRESSURE_SYNC_FENCE}\\s*\\r?\\n([\\s\\S]*?)\\r?\\n\`\`\``, "g");
    const matches = [...reconciliationText.matchAll(fencePattern)];
    if (matches.length === 0) {
        throw new errors_1.RuntimeError({
            message: "Structural-pressure sync rejected because reconciliation evidence does not include an explicit sync payload.",
            code: "STRUCTURAL_PRESSURE_SYNC_REJECTED",
            exitCode: errors_1.RuntimeExitCode.ERROR,
            details: [
                `Add one \`\`\`${contracts_1.STRUCTURAL_PRESSURE_SYNC_FENCE}\`\`\` fenced JSON block to '${reconciliationPath}' with the deduped current-state verdict.`
            ]
        });
    }
    if (matches.length > 1) {
        throw new errors_1.RuntimeError({
            message: "Structural-pressure sync rejected because reconciliation evidence contains multiple sync payloads.",
            code: "STRUCTURAL_PRESSURE_SYNC_REJECTED",
            exitCode: errors_1.RuntimeExitCode.ERROR,
            details: [
                `Keep exactly one \`\`\`${contracts_1.STRUCTURAL_PRESSURE_SYNC_FENCE}\`\`\` fenced JSON block in '${reconciliationPath}'.`
            ]
        });
    }
    try {
        return JSON.parse(matches[0][1]);
    }
    catch (error) {
        throw new errors_1.RuntimeError({
            message: "Structural-pressure sync rejected because the explicit sync payload is not valid JSON.",
            code: "STRUCTURAL_PRESSURE_SYNC_REJECTED",
            exitCode: errors_1.RuntimeExitCode.ERROR,
            details: [
                `${reconciliationPath}: ${error instanceof Error ? error.message : "Could not parse sync payload JSON."}`
            ]
        });
    }
}
function validateSyncPayloadEntries(repositoryRoot, entries, reconciliationPath, milestoneOverviewPath) {
    if (!Array.isArray(entries)) {
        throw new errors_1.RuntimeError({
            message: "Structural-pressure sync rejected because the explicit sync payload is missing an entries array.",
            code: "STRUCTURAL_PRESSURE_SYNC_REJECTED",
            exitCode: errors_1.RuntimeExitCode.ERROR,
            details: ["The sync payload must be a JSON object with an 'entries' array."]
        });
    }
    const seenPaths = new Set();
    const normalizedEntries = entries.map((entry, index) => {
        if (!isRecord(entry)) {
            throw syncPayloadError(`entries[${index}] must be an object.`);
        }
        const normalizedPath = (0, paths_1.parseRepositoryRelativePath)(requireStringField(entry, "path", reconciliationPath, `entries[${index}]`)).normalizedPath;
        if (seenPaths.has(normalizedPath)) {
            throw syncPayloadError(`Duplicate structural-pressure entry for '${normalizedPath}' is not allowed.`);
        }
        seenPaths.add(normalizedPath);
        const status = requireEnumField(entry, "status", contracts_1.STRUCTURAL_PRESSURE_STATUSES, reconciliationPath, `entries[${index}]`);
        const severity = requireEnumField(entry, "severity", contracts_1.STRUCTURAL_PRESSURE_SEVERITIES, reconciliationPath, `entries[${index}]`);
        const summary = requireStringField(entry, "summary", reconciliationPath, `entries[${index}]`).trim();
        if (summary.length === 0) {
            throw syncPayloadError(`entries[${index}].summary must not be empty.`);
        }
        const evidencePaths = normalizeEvidencePaths(entry.evidence_paths, reconciliationPath, `entries[${index}]`);
        for (const evidencePath of evidencePaths) {
            (0, paths_1.resolveRepositoryRelativePath)(repositoryRoot, evidencePath);
        }
        const structuralDelta = (0, delta_evidence_1.normalizeStructuralPressureDeltaEvidence)(entry.structural_delta, normalizedPath, reconciliationPath, `entries[${index}]`, syncPayloadError);
        return {
            path: normalizedPath,
            status,
            severity,
            summary,
            evidence_paths: evidencePaths,
            source_milestone_reconciliation: reconciliationPath,
            source_milestone_overview: milestoneOverviewPath,
            ...(structuralDelta === undefined ? {} : { structural_delta: structuralDelta })
        };
    });
    return normalizedEntries.sort((left, right) => left.path.localeCompare(right.path));
}
function requireStringField(input, key, filePath, context = "state") {
    const value = input[key];
    if (typeof value !== "string" || value.trim().length === 0) {
        throw invalidStateError(filePath, `${context}.${key} must be a non-empty string.`);
    }
    return value;
}
function requireEnumField(input, key, values, filePath, context = "state") {
    const value = requireStringField(input, key, filePath, context);
    if (!values.includes(value)) {
        throw invalidStateError(filePath, `${context}.${key} must be one of: ${values.join(", ")}.`);
    }
    return value;
}
function normalizeEvidencePaths(value, filePath, context) {
    if (value === undefined) {
        return [];
    }
    if (!Array.isArray(value)) {
        throw invalidStateError(filePath, `${context}.evidence_paths must be an array when present.`);
    }
    return value.map((entry, index) => {
        if (typeof entry !== "string" || entry.trim().length === 0) {
            throw invalidStateError(filePath, `${context}.evidence_paths[${index}] must be a non-empty string.`);
        }
        return (0, planning_document_utils_1.toRepositoryLikePath)((0, paths_1.parseRepositoryRelativePath)(entry).normalizedPath);
    });
}
function requireAcceptedStructuralPressureReconciliation(reconciliationText, reconciliationPath) {
    const reviewStatusMatch = reconciliationText.match(/^##[ \t]+Review Status[ \t]*\r?\n\s*([^\r\n]+)/m);
    const reviewStatus = reviewStatusMatch?.[1].trim() ?? null;
    if (reviewStatus?.startsWith("Accepted.") === true) {
        return;
    }
    throw new errors_1.RuntimeError({
        message: "Structural-pressure sync rejected because milestone reconciliation evidence has not been explicitly accepted.",
        code: "STRUCTURAL_PRESSURE_SYNC_REJECTED",
        exitCode: errors_1.RuntimeExitCode.ERROR,
        details: [
            `Artifact '${reconciliationPath}' must contain the command-owned accepted Review Status produced by reconciliation accept before sync can update derived state.`
        ]
    });
}
function invalidStateError(filePath, detail) {
    return new errors_1.RuntimeError({
        message: "Structural-pressure report failed because the derived state file is malformed.",
        code: "STRUCTURAL_PRESSURE_STATE_INVALID",
        exitCode: errors_1.RuntimeExitCode.ERROR,
        details: [`${filePath}: ${detail}`]
    });
}
function syncPayloadError(detail) {
    return new errors_1.RuntimeError({
        message: "Structural-pressure sync rejected because the explicit sync payload is invalid.",
        code: "STRUCTURAL_PRESSURE_SYNC_REJECTED",
        exitCode: errors_1.RuntimeExitCode.ERROR,
        details: [detail]
    });
}
function isRecord(value) {
    return typeof value === "object" && value !== null;
}
