import { readFile } from "node:fs/promises";
import { resolve } from "node:path";
import { normalizeProjectRelativePath } from "./snapshot-policy.js";
import { hashBuffer } from "./snapshot-service.js";
export async function validateRevertSelection(cwd, changeSets) {
    const expectedStates = collectExpectedFileStates(changeSets);
    const conflicts = [];
    for (const state of expectedStates.values()) {
        const relativePath = normalizeProjectRelativePath(cwd, state.path);
        if (!relativePath) {
            conflicts.push({ path: state.path, reason: "unsafe-path", message: "Path is outside the project." });
            continue;
        }
        if (state.file.status === "skipped") {
            conflicts.push({
                path: relativePath,
                reason: "non-revertible",
                message: state.file.skippedReason ?? "Skipped file cannot be reverted safely.",
            });
            continue;
        }
        const currentHash = await readCurrentHash(cwd, relativePath);
        if (state.expectedMissing) {
            if (currentHash !== undefined) {
                conflicts.push({
                    path: relativePath,
                    reason: "unexpected-file",
                    currentHash,
                    message: "Expected file to be missing before revert, but it exists.",
                });
            }
            continue;
        }
        if (!state.expectedHash) {
            conflicts.push({
                path: relativePath,
                reason: "non-revertible",
                message: "Missing expected after-state hash.",
            });
            continue;
        }
        if (currentHash === undefined) {
            conflicts.push({
                path: relativePath,
                reason: "expected-missing",
                expectedHash: state.expectedHash,
                message: "Expected file content before revert, but file is missing.",
            });
            continue;
        }
        if (currentHash !== state.expectedHash) {
            conflicts.push({
                path: relativePath,
                reason: "current-hash-mismatch",
                expectedHash: state.expectedHash,
                currentHash,
                message: "Current file content differs from the recorded change-set after-state.",
            });
        }
    }
    return { ok: conflicts.length === 0, conflicts };
}
function collectExpectedFileStates(changeSets) {
    const states = new Map();
    for (const changeSet of [...changeSets].sort((a, b) => b.id - a.id)) {
        for (const file of changeSet.files) {
            if (states.has(file.path))
                continue;
            states.set(file.path, {
                path: file.path,
                file,
                expectedHash: file.currentExpectedHash ?? file.afterHash,
                expectedMissing: file.status === "deleted",
            });
        }
    }
    return states;
}
async function readCurrentHash(cwd, relativePath) {
    try {
        return hashBuffer(await readFile(resolve(cwd, relativePath)));
    }
    catch (error) {
        if (isFileNotFoundError(error))
            return undefined;
        throw error;
    }
}
function isFileNotFoundError(error) {
    return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
}
//# sourceMappingURL=revert-validation.js.map