"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DestinationSafetyError = exports.DESTINATION_REJECTION_CODES = void 0;
exports.validateWriteDestination = validateWriteDestination;
exports.assertWriteDestination = assertWriteDestination;
exports.assertCanonicalWriteTarget = assertCanonicalWriteTarget;
const path_contract_1 = require("./path-contract");
exports.DESTINATION_REJECTION_CODES = [
    "unsafe_segment",
    "invalid_path_form",
    "reserved_location",
    "missing_target"
];
class DestinationSafetyError extends Error {
    code;
    path;
    reason;
    constructor(rejection) {
        super(rejection.reason);
        this.name = "DestinationSafetyError";
        this.code = rejection.code;
        this.path = rejection.path;
        this.reason = rejection.reason;
    }
}
exports.DestinationSafetyError = DestinationSafetyError;
const RESERVED_SEGMENTS = new Set([
    ".git",
    ".hg",
    ".svn",
    ".jj"
]);
const UNSAFE_SEGMENTS = new Set([
    "node_modules",
    ".pnpm-store",
    ".npm",
    ".yarn",
    ".cache",
    ".turbo",
    "dist",
    "build",
    "out",
    "coverage",
    ".nyc_output",
    "test-results",
    "playwright-report",
    ".agents",
    ".codex"
]);
function validateWriteDestination(input, options = {}) {
    if (typeof input === "string" && input === "") {
        return {
            ok: false,
            rejection: createRejection("missing_target", input, "Destination path is required.")
        };
    }
    const inputPath = typeof input === "string" ? input : input.normalizedPath;
    if (typeof input === "string") {
        const rawSegments = input.split("/");
        if (rawSegments.some((segment) => segment === "")) {
            return {
                ok: false,
                rejection: createRejection("invalid_path_form", input, `Destination must use a canonical repository-relative path: ${input}`)
            };
        }
        if (rawSegments.some((segment) => segment === "." || segment === "..")) {
            return {
                ok: false,
                rejection: createRejection("invalid_path_form", input, `Destination must not contain '.' or '..' segments: ${input}`)
            };
        }
    }
    let repositoryRelativePath;
    try {
        repositoryRelativePath =
            typeof input === "string" ? (0, path_contract_1.parseRepositoryRelativePath)(input) : input;
    }
    catch (error) {
        return {
            ok: false,
            rejection: createRejection("invalid_path_form", inputPath, error instanceof Error ? error.message : `Invalid destination path: ${inputPath}`)
        };
    }
    if (typeof input === "string" && input !== repositoryRelativePath.normalizedPath) {
        return {
            ok: false,
            rejection: createRejection("invalid_path_form", input, `Destination must use the canonical repository-relative path '${repositoryRelativePath.normalizedPath}'.`)
        };
    }
    const segmentRejection = checkSegmentPolicy(repositoryRelativePath.segments, repositoryRelativePath.normalizedPath);
    if (segmentRejection !== null) {
        return { ok: false, rejection: segmentRejection };
    }
    if (options.canonicalPath !== undefined) {
        const canonicalPath = typeof options.canonicalPath === "string"
            ? (0, path_contract_1.parseRepositoryRelativePath)(options.canonicalPath)
            : options.canonicalPath;
        if (repositoryRelativePath.normalizedPath !== canonicalPath.normalizedPath) {
            return {
                ok: false,
                rejection: createRejection("invalid_path_form", repositoryRelativePath.normalizedPath, `Destination must match canonical target '${canonicalPath.normalizedPath}'.`)
            };
        }
    }
    return {
        ok: true,
        value: {
            repositoryRelativePath
        }
    };
}
function assertWriteDestination(input, options = {}) {
    const result = validateWriteDestination(input, options);
    if (!result.ok) {
        throw new DestinationSafetyError(result.rejection);
    }
    return result.value;
}
function assertCanonicalWriteTarget(input, canonicalPath) {
    return assertWriteDestination(input, { canonicalPath }).repositoryRelativePath;
}
function checkSegmentPolicy(segments, normalizedPath) {
    for (const segment of segments) {
        if (RESERVED_SEGMENTS.has(segment)) {
            return createRejection("reserved_location", normalizedPath, `Destination targets reserved repository segment '${segment}'.`);
        }
        if (UNSAFE_SEGMENTS.has(segment) || /\s/.test(segment)) {
            return createRejection("unsafe_segment", normalizedPath, UNSAFE_SEGMENTS.has(segment)
                ? `Destination contains unsafe segment '${segment}'.`
                : `Destination contains whitespace in segment '${segment}'.`);
        }
    }
    return null;
}
function createRejection(code, rejectedPath, reason) {
    return {
        code,
        path: rejectedPath,
        reason
    };
}
