"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.compareRepositoryMigrationPreservation = compareRepositoryMigrationPreservation;
exports.createRepositoryPlanningManifestSync = createRepositoryPlanningManifestSync;
exports.createRepositoryMigrationMappingInventorySync = createRepositoryMigrationMappingInventorySync;
exports.computeRepositoryMigrationCanonicalGuardSync = computeRepositoryMigrationCanonicalGuardSync;
exports.readRepositoryMigrationRehearsalMarkerSync = readRepositoryMigrationRehearsalMarkerSync;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const legacy_compatibility_projection_1 = require("../legacy-compatibility-projection");
const contracts_1 = require("./contracts");
const filesystem_1 = require("./filesystem");
const validation_1 = require("./validation");
function compareRepositoryMigrationPreservation(source, migrated, plan) {
    const mappingsBySource = new Map();
    const canonicalSpecificationRefs = new Map(plan.workUnits.flatMap((unit) => unit.specifications.map((specification) => [
        specification.sourceRef,
        specification.ref
    ])));
    let generatedArtifactCount = 0;
    for (const unit of plan.workUnits) {
        if (!unit.actionable)
            continue;
        for (const mapping of unit.artifactMappings) {
            if (mapping.sourcePath === null) {
                generatedArtifactCount += 1;
                continue;
            }
            const destinations = mappingsBySource.get(mapping.sourcePath) ?? [];
            mappingsBySource.set(mapping.sourcePath, [...destinations, mapping.destinationPath]);
        }
    }
    const migratedByPath = new Map(migrated.entries.map((entry) => [entry.path, entry]));
    const missingSourcePaths = [];
    const missingDestinationPaths = [];
    const duplicateSourceMappings = [];
    const authoredBodyMismatches = [];
    const safeUnknownFieldMismatches = [];
    const lifecycleEvidenceMismatches = [];
    const contractualTimestampMismatches = [];
    const stableIdentityMismatches = [];
    let accountedArtifactCount = 0;
    for (const sourceEntry of source.entries) {
        const destinations = mappingsBySource.get(sourceEntry.path) ?? [];
        if (destinations.length === 0) {
            missingSourcePaths.push(sourceEntry.path);
            continue;
        }
        if (destinations.length > 1) {
            duplicateSourceMappings.push(sourceEntry.path);
            continue;
        }
        const destination = migratedByPath.get(destinations[0]);
        if (destination === undefined) {
            missingDestinationPaths.push(destinations[0]);
            continue;
        }
        accountedArtifactCount += 1;
        if (sourceEntry.authoredBodyDigest !== destination.authoredBodyDigest) {
            authoredBodyMismatches.push(sourceEntry.path);
        }
        if (sourceEntry.safeUnknownFieldsDigest !== destination.safeUnknownFieldsDigest) {
            safeUnknownFieldMismatches.push(sourceEntry.path);
        }
        if (sourceEntry.lifecycleEvidenceDigest !== destination.lifecycleEvidenceDigest
            && sourceEntry.migrationNormalizedLifecycleEvidenceDigest
                !== destination.migrationNormalizedLifecycleEvidenceDigest) {
            lifecycleEvidenceMismatches.push(sourceEntry.path);
        }
        if (sourceEntry.contractualTimestampDigest !== destination.contractualTimestampDigest) {
            contractualTimestampMismatches.push(sourceEntry.path);
        }
        if (!(0, validation_1.stableIdentityPreserved)(sourceEntry.identity, destination.identity, canonicalSpecificationRefs)) {
            stableIdentityMismatches.push(sourceEntry.path);
        }
    }
    const blocking = [
        missingSourcePaths,
        missingDestinationPaths,
        duplicateSourceMappings,
        authoredBodyMismatches,
        safeUnknownFieldMismatches,
        lifecycleEvidenceMismatches,
        contractualTimestampMismatches,
        stableIdentityMismatches
    ].some((entries) => entries.length > 0);
    return {
        verdict: blocking ? "blocked" : "accepted",
        sourceArtifactCount: source.entryCount,
        accountedArtifactCount,
        generatedArtifactCount,
        missingSourcePaths: missingSourcePaths.sort(),
        missingDestinationPaths: missingDestinationPaths.sort(),
        duplicateSourceMappings: duplicateSourceMappings.sort(),
        authoredBodyMismatches: authoredBodyMismatches.sort(),
        safeUnknownFieldMismatches: safeUnknownFieldMismatches.sort(),
        lifecycleEvidenceMismatches: lifecycleEvidenceMismatches.sort(),
        contractualTimestampMismatches: contractualTimestampMismatches.sort(),
        stableIdentityMismatches: stableIdentityMismatches.sort(),
        approvedTransformations: [
            "Canonical workflow_level and relationship coordinates are rewritten by the preview-bound migration plan.",
            "Legacy specification refs are normalized only when their declared specification id resolves in the canonical spec index.",
            "Artifact roles and ids for generated/canonical work overviews are transformed as declared by the migration mapping.",
            "Basic and Structured implementation_order plus parent-local Structured sequence metadata are inserted exactly as declared by the numbered-root plan.",
            "Path-only readiness revision pointers are rebound with explicit workspace-numbered-root-migration provenance.",
            "Empty numbered source directories are removed after their artifacts are transactionally retired."
        ],
        approvedGaps: []
    };
}
function createRepositoryPlanningManifestSync(repositoryRootInput) {
    const repositoryRoot = node_fs_1.default.realpathSync(node_path_1.default.resolve(repositoryRootInput));
    const planningRoot = node_path_1.default.join(repositoryRoot, ".day-shift", "planning");
    (0, filesystem_1.requireDirectory)(planningRoot, "Canonical planning root");
    (0, filesystem_1.rejectSymlinkPath)(repositoryRoot, planningRoot, "Canonical planning root");
    const entries = (0, filesystem_1.walkFiles)(planningRoot).map((absolutePath) => {
        const contents = node_fs_1.default.readFileSync(absolutePath);
        const repositoryRelativePath = (0, filesystem_1.toPosix)(node_path_1.default.relative(repositoryRoot, absolutePath));
        const stat = node_fs_1.default.statSync(absolutePath);
        const markdownText = repositoryRelativePath.endsWith(".md")
            ? contents.toString("utf8")
            : null;
        return {
            path: repositoryRelativePath,
            bytes: contents.byteLength,
            mode: (0, filesystem_1.modeToken)(stat.mode),
            contentDigest: (0, filesystem_1.sha256)(contents),
            authoredBodyDigest: markdownText === null
                ? null
                : (0, filesystem_1.sha256)((0, filesystem_1.authoredBody)(markdownText)),
            safeUnknownFieldsDigest: markdownText === null
                ? null
                : (0, filesystem_1.frontMatterEvidenceDigest)(markdownText, validation_1.SAFE_UNKNOWN_FRONT_MATTER_FIELDS),
            lifecycleEvidenceDigest: markdownText === null
                ? null
                : (0, filesystem_1.frontMatterEvidenceDigest)(markdownText, validation_1.LIFECYCLE_FRONT_MATTER_FIELDS),
            migrationNormalizedLifecycleEvidenceDigest: markdownText === null
                ? null
                : (0, filesystem_1.frontMatterEvidenceDigest)(markdownText, validation_1.MIGRATION_NORMALIZED_LIFECYCLE_FRONT_MATTER_FIELDS),
            contractualTimestampDigest: markdownText === null
                ? null
                : (0, filesystem_1.frontMatterEvidenceDigest)(markdownText, validation_1.CONTRACTUAL_TIMESTAMP_FIELDS),
            identity: markdownText === null ? null : (0, filesystem_1.readManifestIdentity)(markdownText)
        };
    }).sort((left, right) => left.path.localeCompare(right.path));
    const digestInput = {
        protocolVersion: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_PROTOCOL_VERSION,
        rootPath: ".day-shift/planning",
        entries
    };
    return {
        protocolVersion: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_PROTOCOL_VERSION,
        rootPath: ".day-shift/planning",
        entries,
        entryCount: entries.length,
        totalBytes: entries.reduce((total, entry) => total + entry.bytes, 0),
        aggregateDigest: (0, filesystem_1.sha256)((0, filesystem_1.stableJson)(digestInput))
    };
}
function createRepositoryMigrationMappingInventorySync(repositoryRootInput) {
    const repositoryRoot = node_fs_1.default.realpathSync(node_path_1.default.resolve(repositoryRootInput));
    const planningRoot = node_path_1.default.join(repositoryRoot, ".day-shift", "planning");
    (0, filesystem_1.requireDirectory)(planningRoot, "Canonical planning root");
    const numericRoots = node_fs_1.default.readdirSync(planningRoot, { withFileTypes: true })
        .filter((entry) => entry.isDirectory() && /^\d{2}-/.test(entry.name))
        .map((entry) => ({
        prefix: entry.name.slice(0, 2),
        path: `.day-shift/planning/${entry.name}`
    }))
        .sort((left, right) => left.path.localeCompare(right.path));
    const grouped = new Map();
    for (const root of numericRoots) {
        const existing = grouped.get(root.prefix) ?? [];
        grouped.set(root.prefix, [...existing, root.path]);
    }
    const samePrefixRoots = [...grouped.entries()]
        .filter(([, paths]) => paths.length > 1)
        .map(([prefix, paths]) => ({ prefix, paths: [...paths].sort() }))
        .sort((left, right) => left.prefix.localeCompare(right.prefix));
    const expectedPrefixes = Array.from({ length: 28 }, (_, index) => String(index).padStart(2, "0"));
    const absentPrefixes = expectedPrefixes.filter((prefix) => !grouped.has(prefix));
    const projection = (0, legacy_compatibility_projection_1.projectLegacyPlanningCompatibility)({
        repositoryRoot,
        generatedAt: "not-recorded"
    });
    const units = projection.workUnits.map((unit) => ({
        workUnitId: unit.workUnitId,
        sourcePaths: [...unit.sourcePaths].sort(),
        proposalStatus: unit.proposalStatus,
        proposedWorkflowLevel: unit.proposedWorkflowLevel,
        selectedWorkflowLevel: null,
        selectionSource: null,
        ambiguityReasons: unit.ambiguityReasons.map((reason) => ({
            code: reason.code,
            paths: [...reason.paths].sort(),
            message: reason.message
        }))
    })).sort((left, right) => left.workUnitId.localeCompare(right.workUnitId));
    const unresolvedUnitIds = units
        .filter((unit) => unit.proposedWorkflowLevel === null)
        .map((unit) => unit.workUnitId);
    const digestInput = {
        protocolVersion: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_PROTOCOL_VERSION,
        numericRoots,
        samePrefixRoots,
        absentPrefixes,
        compatibilityProposalStatus: projection.proposalStatus,
        units,
        unresolvedUnitIds
    };
    return {
        ...digestInput,
        aggregateDigest: (0, filesystem_1.sha256)((0, filesystem_1.stableJson)(digestInput))
    };
}
function computeRepositoryMigrationCanonicalGuardSync(repositoryRootInput) {
    const repositoryRoot = node_fs_1.default.realpathSync(node_path_1.default.resolve(repositoryRootInput));
    const planningDigest = (0, filesystem_1.digestTree)(node_path_1.default.join(repositoryRoot, ".day-shift", "planning"));
    const specsDigest = (0, filesystem_1.digestTree)(node_path_1.default.join(repositoryRoot, ".day-shift", "specs"));
    const configPath = node_path_1.default.join(repositoryRoot, ".day-shift", "config.toml");
    (0, filesystem_1.requireFile)(configPath, "Canonical configuration");
    (0, filesystem_1.rejectSymlinkPath)(repositoryRoot, configPath, "Canonical configuration");
    const configStat = node_fs_1.default.statSync(configPath);
    const configDigest = (0, filesystem_1.sha256)((0, filesystem_1.stableJson)({
        path: ".day-shift/config.toml",
        mode: (0, filesystem_1.modeToken)(configStat.mode),
        contentDigest: (0, filesystem_1.sha256)(node_fs_1.default.readFileSync(configPath))
    }));
    const aggregateDigest = (0, filesystem_1.sha256)((0, filesystem_1.stableJson)({
        planningDigest,
        specsDigest,
        configDigest
    }));
    return {
        protocolVersion: contracts_1.REPOSITORY_MIGRATION_REHEARSAL_PROTOCOL_VERSION,
        planningDigest,
        specsDigest,
        configDigest,
        aggregateDigest
    };
}
function readRepositoryMigrationRehearsalMarkerSync(repositoryRootInput) {
    const repositoryRoot = (0, filesystem_1.resolveCanonicalRepositoryRoot)(repositoryRootInput);
    const markerPath = node_path_1.default.join(repositoryRoot, ...contracts_1.REPOSITORY_MIGRATION_REHEARSAL_ROOT.split("/"), ...contracts_1.REPOSITORY_MIGRATION_REHEARSAL_MARKER.split("/"));
    return (0, filesystem_1.parseOwnerMarker)(markerPath);
}
