import { lstat } from "node:fs/promises";
import { isAbsolute, relative, resolve, sep } from "node:path";
export const DEFAULT_SNAPSHOT_MAX_FILE_BYTES = 5 * 1024 * 1024;
const DEFAULT_EXCLUDED_SEGMENTS = new Set([
    ".git",
    ".threadwell",
    ".engram",
    "node_modules",
    "dist",
    "dist-test",
    "build",
    "coverage",
    ".next",
    ".nuxt",
    ".turbo",
    ".cache",
    ".parcel-cache",
    "target",
    "release",
    "tmp",
    "temp",
]);
export function createSnapshotPolicy(options = {}) {
    return {
        maxFileBytes: options.maxFileBytes ?? DEFAULT_SNAPSHOT_MAX_FILE_BYTES,
        excludedSegments: new Set(options.excludedSegments ?? DEFAULT_EXCLUDED_SEGMENTS),
    };
}
export function normalizeProjectRelativePath(cwd, candidatePath) {
    const resolvedCwd = resolve(cwd);
    const absolutePath = isAbsolute(candidatePath) ? resolve(candidatePath) : resolve(resolvedCwd, candidatePath);
    const relativePath = relative(resolvedCwd, absolutePath);
    if (!relativePath || relativePath === "")
        return undefined;
    if (relativePath.startsWith("..") || isAbsolute(relativePath))
        return undefined;
    return relativePath.split(sep).join("/");
}
export function isExcludedSnapshotPath(relativePath, policy = createSnapshotPolicy()) {
    const segments = relativePath.split("/").filter(Boolean);
    return segments.some((segment) => policy.excludedSegments.has(segment));
}
export function isLikelyBinaryContent(content) {
    if (content.length === 0)
        return false;
    const sampleLength = Math.min(content.length, 4096);
    for (let index = 0; index < sampleLength; index++) {
        if (content[index] === 0)
            return true;
    }
    return false;
}
export async function evaluateSnapshotFile(cwd, candidatePath, policy = createSnapshotPolicy()) {
    const relativePath = normalizeProjectRelativePath(cwd, candidatePath);
    if (!relativePath)
        return { ok: false, reason: "path-outside-project" };
    const absolutePath = resolve(cwd, relativePath);
    if (isExcludedSnapshotPath(relativePath, policy)) {
        return { ok: false, relativePath, absolutePath, reason: "excluded-path" };
    }
    let stat;
    try {
        stat = await lstat(absolutePath);
    }
    catch (error) {
        if (isFileNotFoundError(error))
            return { ok: false, relativePath, absolutePath, reason: "missing" };
        throw error;
    }
    if (stat.isSymbolicLink())
        return { ok: false, relativePath, absolutePath, reason: "symlink" };
    if (!stat.isFile())
        return { ok: false, relativePath, absolutePath, reason: "not-file" };
    if (stat.size > policy.maxFileBytes)
        return { ok: false, relativePath, absolutePath, reason: "large-file" };
    return { ok: true, relativePath, absolutePath, size: stat.size, binary: false };
}
function isFileNotFoundError(error) {
    return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
}
//# sourceMappingURL=snapshot-policy.js.map