"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizeStructuralPressureDeltaEvidence = normalizeStructuralPressureDeltaEvidence;
const paths_1 = require("../../paths");
const planning_document_utils_1 = require("../planning-document-utils");
const contracts_1 = require("./contracts");
function normalizeStructuralPressureDeltaEvidence(value, entryPath, filePath, context, fail) {
    if (value === undefined) {
        return undefined;
    }
    if (!isRecord(value)) {
        throw fail(`${context}.structural_delta must be an object when present.`);
    }
    if (!isRecord(value.original_owner)) {
        throw fail(`${context}.structural_delta.original_owner must be an object.`);
    }
    const originalOwnerPath = normalizeStructuralPressureDeltaPath(value.original_owner.path, `${context}.structural_delta.original_owner.path`, fail);
    if (originalOwnerPath !== entryPath) {
        throw fail(`${context}.structural_delta.original_owner.path must equal the containing entry path '${entryPath}'.`);
    }
    const before = normalizeStructuralPressureOwnerMetrics(value.original_owner.before, `${context}.structural_delta.original_owner.before`, fail);
    const after = normalizeStructuralPressureOwnerMetrics(value.original_owner.after, `${context}.structural_delta.original_owner.after`, fail);
    const facadeDependencies = normalizeStructuralPressureDeltaPaths(value.facade_dependencies, `${context}.structural_delta.facade_dependencies`, fail);
    const reverseDependencies = normalizeStructuralPressureDeltaPaths(value.reverse_dependencies, `${context}.structural_delta.reverse_dependencies`, fail);
    const facadeDependencyDirection = normalizeStructuralPressureDeltaEnum(value.facade_dependency_direction, contracts_1.STRUCTURAL_PRESSURE_FACADE_DEPENDENCY_DIRECTIONS, `${context}.structural_delta.facade_dependency_direction`, fail);
    const residualClassification = normalizeStructuralPressureDeltaEnum(value.residual_classification, contracts_1.STRUCTURAL_PRESSURE_RESIDUAL_CLASSIFICATIONS, `${context}.structural_delta.residual_classification`, fail);
    const derivedDirection = deriveStructuralPressureFacadeDependencyDirection(facadeDependencies, reverseDependencies);
    if (facadeDependencyDirection !== derivedDirection) {
        throw fail(`${context}.structural_delta.facade_dependency_direction must be '${derivedDirection}' for the recorded facade and reverse dependency sets.`);
    }
    return {
        original_owner: {
            path: originalOwnerPath,
            before,
            after
        },
        facade_dependencies: facadeDependencies,
        reverse_dependencies: reverseDependencies,
        facade_dependency_direction: facadeDependencyDirection,
        residual_classification: residualClassification
    };
}
function normalizeStructuralPressureOwnerMetrics(value, context, fail) {
    if (!isRecord(value)) {
        throw fail(`${context} must be an object.`);
    }
    const lineCount = normalizeStructuralPressureMetric(value.line_count, `${context}.line_count`, fail);
    const exportCount = normalizeStructuralPressureMetric(value.export_count, `${context}.export_count`, fail);
    const largestFunctionLines = normalizeStructuralPressureMetric(value.largest_function_lines, `${context}.largest_function_lines`, fail);
    if (largestFunctionLines > lineCount) {
        throw fail(`${context}.largest_function_lines must not exceed line_count.`);
    }
    return {
        line_count: lineCount,
        export_count: exportCount,
        largest_function_lines: largestFunctionLines
    };
}
function normalizeStructuralPressureMetric(value, context, fail) {
    if (!Number.isSafeInteger(value) || value < 0) {
        throw fail(`${context} must be a non-negative safe integer.`);
    }
    return value;
}
function normalizeStructuralPressureDeltaPaths(value, context, fail) {
    if (!Array.isArray(value)) {
        throw fail(`${context} must be an array.`);
    }
    const paths = value.map((entry, index) => normalizeStructuralPressureDeltaPath(entry, `${context}[${index}]`, fail));
    const uniquePaths = new Set(paths);
    if (uniquePaths.size !== paths.length) {
        throw fail(`${context} must not contain duplicate paths.`);
    }
    return [...uniquePaths].sort((left, right) => left.localeCompare(right));
}
function normalizeStructuralPressureDeltaPath(value, context, fail) {
    if (typeof value !== "string" || value.trim().length === 0) {
        throw fail(`${context} must be a non-empty repository-relative path.`);
    }
    try {
        return (0, planning_document_utils_1.toRepositoryLikePath)((0, paths_1.parseRepositoryRelativePath)(value).normalizedPath);
    }
    catch (error) {
        throw fail(`${context} must be a valid repository-relative path: ${error instanceof Error ? error.message : "invalid path"}`);
    }
}
function normalizeStructuralPressureDeltaEnum(value, values, context, fail) {
    if (typeof value !== "string" || !values.includes(value)) {
        throw fail(`${context} must be one of: ${values.join(", ")}.`);
    }
    return value;
}
function deriveStructuralPressureFacadeDependencyDirection(facadeDependencies, reverseDependencies) {
    if (facadeDependencies.length > 0 && reverseDependencies.length > 0) {
        return "bidirectional";
    }
    if (facadeDependencies.length > 0) {
        return "facade-to-extracted";
    }
    if (reverseDependencies.length > 0) {
        return "extracted-to-facade";
    }
    return "none";
}
function isRecord(value) {
    return typeof value === "object" && value !== null;
}
