"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildRepositoryMigrationRehearsalSync = buildRepositoryMigrationRehearsalSync;
exports.createRepositoryMigrationMappingDocument = createRepositoryMigrationMappingDocument;
exports.refreshRepositoryMigrationMappingDocumentSync = refreshRepositoryMigrationMappingDocumentSync;
exports.readRepositoryMigrationMappingDocumentSync = readRepositoryMigrationMappingDocumentSync;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const contracts_1 = require("./contracts");
const filesystem_1 = require("./filesystem");
const preservation_1 = require("./preservation");
const validation_1 = require("./validation");
/**
 * Rebuild the one repository-owned migration rehearsal workspace.
 *
 * This is deliberately synchronous: target validation, cleanup, copy, and
 * canonical guard comparison form one auditable operator boundary.
 */
function buildRepositoryMigrationRehearsalSync(options) {
    const repositoryRoot = (0, filesystem_1.resolveCanonicalRepositoryRoot)(options.repositoryRoot);
    const target = (0, filesystem_1.resolveExactRehearsalTarget)(repositoryRoot, options.targetPath ?? contracts_1.REPOSITORY_MIGRATION_REHEARSAL_ROOT);
    const sources = (0, filesystem_1.resolveCanonicalSources)(repositoryRoot);
    const canonicalGuardBefore = (0, preservation_1.computeRepositoryMigrationCanonicalGuardSync)(repositoryRoot);
    const sourceManifest = (0, preservation_1.createRepositoryPlanningManifestSync)(repositoryRoot);
    const mappingInventory = (0, preservation_1.createRepositoryMigrationMappingInventorySync)(repositoryRoot);
    const referencedSpecificationPaths = (0, filesystem_1.collectReferencedSpecifications)(sourceManifest);
    (0, filesystem_1.validateReferencedSpecifications)(repositoryRoot, referencedSpecificationPaths);
    (0, filesystem_1.removeOwnedTargetIfPresent)(repositoryRoot, target);
    node_fs_1.default.mkdirSync(target.absolutePath, { recursive: true, mode: 0o700 });
    (0, filesystem_1.writeOwnerMarker)(repositoryRoot, target);
    (0, filesystem_1.copyTreePreservingBytesAndModes)(sources.planning, node_path_1.default.join(target.absolutePath, ".day-shift", "planning"));
    (0, filesystem_1.copyFilePreservingBytesAndMode)(sources.config, node_path_1.default.join(target.absolutePath, ".day-shift", "config.toml"));
    (0, filesystem_1.copyTreePreservingBytesAndModes)(sources.specs, node_path_1.default.join(target.absolutePath, ".day-shift", "specs"));
    const isolatedManifest = (0, preservation_1.createRepositoryPlanningManifestSync)(target.absolutePath);
    if ((0, filesystem_1.stableJson)(sourceManifest) !== (0, filesystem_1.stableJson)(isolatedManifest)) {
        throw new contracts_1.RepositoryMigrationRehearsalError("unsafe-source", "The isolated planning manifest does not match the canonical source manifest after copy.", false);
    }
    const canonicalGuardAfter = (0, preservation_1.computeRepositoryMigrationCanonicalGuardSync)(repositoryRoot);
    const canonicalGuardMatched = canonicalGuardBefore.aggregateDigest === canonicalGuardAfter.aggregateDigest;
    if (!canonicalGuardMatched) {
        throw new contracts_1.RepositoryMigrationRehearsalError("unsafe-source", "Canonical planning, specifications, or configuration changed during rehearsal build.", false);
    }
    const deterministic = {
        protocolVersion: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_PROTOCOL_VERSION,
        targetPath: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_ROOT,
        sourceManifestDigest: sourceManifest.aggregateDigest,
        isolatedManifestDigest: isolatedManifest.aggregateDigest,
        referencedSpecificationPaths,
        mappingInventoryDigest: mappingInventory.aggregateDigest,
        canonicalGuardDigest: canonicalGuardAfter.aggregateDigest
    };
    return {
        protocolVersion: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_PROTOCOL_VERSION,
        operation: "build",
        targetPath: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_ROOT,
        markerPath: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_MARKER,
        disposable: true,
        sourceManifest,
        isolatedManifest,
        referencedSpecificationPaths,
        mappingInventory,
        canonicalGuardBefore,
        canonicalGuardAfter,
        canonicalGuardMatched,
        deterministicDigest: (0, filesystem_1.sha256)((0, filesystem_1.stableJson)(deterministic)),
        volatile: (0, filesystem_1.readVolatileEvidence)(repositoryRoot)
    };
}
function createRepositoryMigrationMappingDocument(build, selectedLevels, rationales = {}) {
    const inventoryIds = build.mappingInventory.units.map((unit) => unit.workUnitId);
    const suppliedIds = Object.keys(selectedLevels).sort();
    if ((0, filesystem_1.stableJson)(suppliedIds) !== (0, filesystem_1.stableJson)([...inventoryIds].sort())) {
        const missing = inventoryIds.filter((id) => selectedLevels[id] === undefined);
        const unknown = suppliedIds.filter((id) => !build.mappingInventory.units.some((unit) => unit.workUnitId === id));
        throw new contracts_1.RepositoryMigrationRehearsalError("invalid-mapping", `Mapping selections must enumerate every work unit exactly once (missing: ${missing.join(", ") || "none"}; unknown: ${unknown.join(", ") || "none"}).`);
    }
    const selections = build.mappingInventory.units.map((unit) => {
        const workflowLevel = selectedLevels[unit.workUnitId];
        if (!(0, validation_1.isWorkflowLevel)(workflowLevel)) {
            throw new contracts_1.RepositoryMigrationRehearsalError("invalid-mapping", `Mapping selection '${unit.workUnitId}' has unsupported workflow level '${String(workflowLevel)}'.`);
        }
        const rationale = (rationales[unit.workUnitId] ?? (unit.proposedWorkflowLevel === workflowLevel
            ? `Explicitly accepts compatibility proposal '${workflowLevel}'.`
            : `Explicit reviewed override selects '${workflowLevel}' for compatibility evidence that had no safe proposal.`)).trim();
        if (rationale.length === 0) {
            throw new contracts_1.RepositoryMigrationRehearsalError("invalid-mapping", `Mapping selection '${unit.workUnitId}' requires a non-empty rationale.`);
        }
        return {
            workUnitId: unit.workUnitId,
            workflowLevel,
            sourcePathCount: unit.sourcePaths.length,
            sourcePathsDigest: (0, filesystem_1.sha256)((0, filesystem_1.stableJson)([...unit.sourcePaths].sort())),
            rationale
        };
    }).sort((left, right) => left.workUnitId.localeCompare(right.workUnitId));
    const digestInput = {
        protocolVersion: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_PROTOCOL_VERSION,
        kind: "day-shift-phase-07-repository-migration-mapping",
        sourceManifestDigest: build.sourceManifest.aggregateDigest,
        mappingInventoryDigest: build.mappingInventory.aggregateDigest,
        numericRoots: build.mappingInventory.numericRoots,
        samePrefixRoots: build.mappingInventory.samePrefixRoots,
        absentPrefixes: build.mappingInventory.absentPrefixes,
        selections
    };
    return {
        ...digestInput,
        mappingDigest: (0, filesystem_1.sha256)((0, filesystem_1.stableJson)(digestInput))
    };
}
function refreshRepositoryMigrationMappingDocumentSync(options) {
    const repositoryRoot = (0, filesystem_1.resolveCanonicalRepositoryRoot)(options.repositoryRoot);
    const previous = readRepositoryMigrationMappingDocumentSync(repositoryRoot);
    const build = buildRepositoryMigrationRehearsalSync({ repositoryRoot });
    const selectedLevels = Object.fromEntries(previous.selections.map((selection) => [
        selection.workUnitId,
        selection.workflowLevel
    ]));
    const rationales = Object.fromEntries(previous.selections.map((selection) => [
        selection.workUnitId,
        selection.rationale
    ]));
    const refreshed = createRepositoryMigrationMappingDocument(build, selectedLevels, rationales);
    (0, validation_1.writeTrackedJsonSync)(repositoryRoot, contracts_1.REPOSITORY_MIGRATION_MAPPING_PATH, refreshed);
    return refreshed;
}
function readRepositoryMigrationMappingDocumentSync(repositoryRootInput, evidence) {
    const repositoryRoot = (0, filesystem_1.resolveCanonicalRepositoryRoot)(repositoryRootInput);
    const mappingPath = node_path_1.default.join(repositoryRoot, ...contracts_1.REPOSITORY_MIGRATION_MAPPING_PATH.split("/"));
    (0, filesystem_1.requireFile)(mappingPath, "Phase 07 migration mapping");
    (0, filesystem_1.rejectSymlinkPath)(repositoryRoot, mappingPath, "Phase 07 migration mapping");
    let parsed;
    try {
        parsed = JSON.parse(node_fs_1.default.readFileSync(mappingPath, "utf8"));
    }
    catch {
        throw new contracts_1.RepositoryMigrationRehearsalError("invalid-mapping", "Phase 07 migration mapping is not valid JSON.");
    }
    (0, validation_1.validateMappingDocument)(parsed, evidence);
    return parsed;
}
