"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.computeContentRevisionSync = computeContentRevisionSync;
exports.captureContentRevisionPreconditionSync = captureContentRevisionPreconditionSync;
exports.captureDestinationPresencePreconditionSync = captureDestinationPresencePreconditionSync;
exports.revalidateMutationPreconditionsSync = revalidateMutationPreconditionsSync;
exports.serializeMutationPrecondition = serializeMutationPrecondition;
exports.resolvePortableMutationPreconditionSync = resolvePortableMutationPreconditionSync;
const node_fs_1 = __importDefault(require("node:fs"));
const node_crypto_1 = require("node:crypto");
const canonical_write_target_js_1 = require("../paths/canonical-write-target.js");
function computeContentRevisionSync(runtimePath) {
    const stats = node_fs_1.default.statSync(runtimePath, { throwIfNoEntry: false });
    if (stats === undefined) {
        throw new Error(`Cannot compute a content revision for missing file '${runtimePath}'.`);
    }
    if (!stats.isFile()) {
        throw new Error(`Cannot compute a content revision for non-file path '${runtimePath}'.`);
    }
    return (0, node_crypto_1.createHash)("sha256").update(node_fs_1.default.readFileSync(runtimePath)).digest("hex");
}
function captureContentRevisionPreconditionSync(target) {
    validateTarget(target);
    return {
        kind: "content-revision",
        repositoryRelativePath: target.repositoryRelativePath,
        runtimePath: target.runtimePath,
        expectedRevision: computeContentRevisionSync(target.runtimePath)
    };
}
function captureDestinationPresencePreconditionSync(target) {
    validateTarget(target);
    return {
        kind: "destination-presence",
        repositoryRelativePath: target.repositoryRelativePath,
        runtimePath: target.runtimePath,
        expectedPresence: observePresence(target.runtimePath)
    };
}
/** Revalidates every supplied expectation and reports all conflicts before a caller writes. */
function revalidateMutationPreconditionsSync(preconditions) {
    if (!Array.isArray(preconditions)) {
        throw new TypeError("Mutation preconditions must be an array.");
    }
    const conflicts = [];
    for (const precondition of preconditions) {
        validateTarget(precondition);
        if (precondition.kind === "content-revision") {
            const observedRevision = observeRevision(precondition.runtimePath);
            if (observedRevision !== precondition.expectedRevision) {
                conflicts.push(createConflict(precondition.repositoryRelativePath, precondition.kind, precondition.expectedRevision, observedRevision ?? "missing"));
            }
            continue;
        }
        if (precondition.kind === "destination-presence") {
            const observedPresence = observePresence(precondition.runtimePath);
            if (observedPresence !== precondition.expectedPresence) {
                conflicts.push(createConflict(precondition.repositoryRelativePath, precondition.kind, precondition.expectedPresence, observedPresence));
            }
            continue;
        }
        throw new TypeError("Unsupported mutation precondition kind.");
    }
    return { ok: conflicts.length === 0, conflicts };
}
function serializeMutationPrecondition(precondition) {
    validateTarget(precondition);
    return {
        path: precondition.repositoryRelativePath,
        kind: precondition.kind,
        expectedState: precondition.kind === "content-revision"
            ? precondition.expectedRevision
            : precondition.expectedPresence
    };
}
function resolvePortableMutationPreconditionSync(repositoryRoot, precondition) {
    if (precondition === null || typeof precondition !== "object") {
        throw new TypeError("A portable mutation precondition is required.");
    }
    const target = (0, canonical_write_target_js_1.resolveCanonicalWriteTargetSync)(repositoryRoot, precondition.path);
    if (precondition.kind === "content-revision") {
        if (!/^[a-f0-9]{64}$/u.test(precondition.expectedState)) {
            throw new TypeError("Content-revision preconditions require a lowercase SHA-256 state.");
        }
        return {
            kind: "content-revision",
            repositoryRelativePath: target.repositoryRelativePath,
            runtimePath: target.runtimePath,
            expectedRevision: precondition.expectedState
        };
    }
    if (precondition.kind === "destination-presence") {
        if (precondition.expectedState !== "present" && precondition.expectedState !== "absent") {
            throw new TypeError("Destination-presence preconditions require present or absent state.");
        }
        return {
            kind: "destination-presence",
            repositoryRelativePath: target.repositoryRelativePath,
            runtimePath: target.runtimePath,
            expectedPresence: precondition.expectedState
        };
    }
    throw new TypeError("Unsupported portable mutation precondition kind.");
}
function observeRevision(runtimePath) {
    const stats = node_fs_1.default.statSync(runtimePath, { throwIfNoEntry: false });
    if (stats === undefined || !stats.isFile()) {
        return null;
    }
    return (0, node_crypto_1.createHash)("sha256").update(node_fs_1.default.readFileSync(runtimePath)).digest("hex");
}
function observePresence(runtimePath) {
    return node_fs_1.default.lstatSync(runtimePath, { throwIfNoEntry: false }) === undefined ? "absent" : "present";
}
function createConflict(repositoryRelativePath, expectationKind, expectedState, observedState) {
    return {
        path: repositoryRelativePath,
        expectationKind,
        expectedState,
        observedState,
        refreshPreviewRequired: true,
        guidance: "Refresh the preview before retrying this mutation."
    };
}
function validateTarget(target) {
    if (target === null || typeof target !== "object") {
        throw new TypeError("A mutation precondition target is required.");
    }
    if (typeof target.repositoryRelativePath !== "string" || target.repositoryRelativePath === "") {
        throw new TypeError("Mutation preconditions require a repository-relative path.");
    }
    if (typeof target.runtimePath !== "string" || target.runtimePath === "") {
        throw new TypeError("Mutation preconditions require a runtime path.");
    }
}
