"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateModuleContractIntegrity = validateModuleContractIntegrity;
const path = __importStar(require("node:path"));
const node_fs_1 = require("node:fs");
function toWorkspaceAbsolutePath(workspaceRoot, relativePath) {
    return path.join(workspaceRoot, ...relativePath.split('/'));
}
function normalizePathValue(value) {
    return value.replace(/\\/g, '/').trim();
}
function normalizeStringArray(value) {
    if (!Array.isArray(value)) {
        return undefined;
    }
    const normalizedValues = value
        .filter((item) => typeof item === 'string')
        .map((item) => normalizePathValue(item));
    if (normalizedValues.length !== value.length) {
        return undefined;
    }
    return normalizedValues;
}
async function pathExists(targetPath) {
    try {
        await node_fs_1.promises.access(targetPath);
        return true;
    }
    catch {
        return false;
    }
}
function makeResult(id, severity, passed, message) {
    return { id, severity, passed, message };
}
function comparePublicEntrypoints(left, right) {
    if (left.length !== right.length) {
        return false;
    }
    for (let index = 0; index < left.length; index += 1) {
        if (normalizePathValue(left[index]) !== normalizePathValue(right[index])) {
            return false;
        }
    }
    return true;
}
async function readModuleContract(workspaceRoot, contractPath) {
    const fullPath = toWorkspaceAbsolutePath(workspaceRoot, contractPath);
    const content = await node_fs_1.promises.readFile(fullPath, { encoding: 'utf8' });
    try {
        return {
            contract: JSON.parse(content),
        };
    }
    catch {
        return {
            error: `Module contract at ${contractPath} is invalid JSON.`,
        };
    }
}
function getModuleEntries(contract) {
    return Object.entries(contract.modules).sort(([left], [right]) => left.localeCompare(right));
}
async function validateModuleContractIntegrity(workspaceRoot, contract, options) {
    const findings = [];
    const moduleEntries = getModuleEntries(contract);
    if (moduleEntries.length === 0) {
        if (options.checkRegistryPathExists) {
            findings.push({
                result: makeResult('AP-ARCH-005', 'error', true, 'No modules are registered in architecture.json. Module registry path checks are not applicable.'),
            });
        }
        if (options.checkContractFileExists) {
            findings.push({
                result: makeResult('AP-ARCH-006', 'error', true, 'No modules are registered in architecture.json. Module contract file checks are not applicable.'),
            });
        }
        if (options.checkContractIdentityMatchesRegistry) {
            findings.push({
                result: makeResult('AP-ARCH-007', 'error', true, 'No modules are registered in architecture.json. Module contract identity checks are not applicable.'),
            });
        }
        if (options.checkPublicEntrypointsAligned) {
            findings.push({
                result: makeResult('AP-ARCH-008', 'error', true, 'No modules are registered in architecture.json. Module public entrypoint alignment checks are not applicable.'),
            });
        }
        return findings;
    }
    if (options.checkRegistryPathExists) {
        const failures = [];
        for (const [moduleName, moduleReference] of moduleEntries) {
            const modulePath = moduleReference.path;
            if (!modulePath) {
                continue;
            }
            const fullModulePath = toWorkspaceAbsolutePath(workspaceRoot, modulePath);
            try {
                const stats = await node_fs_1.promises.stat(fullModulePath);
                if (!stats.isDirectory()) {
                    failures.push({
                        result: makeResult('AP-ARCH-005', 'error', false, `Module '${moduleName}' is registered at ${modulePath} but the directory does not exist.`),
                        filePath: modulePath,
                    });
                }
            }
            catch {
                failures.push({
                    result: makeResult('AP-ARCH-005', 'error', false, `Module '${moduleName}' is registered at ${modulePath} but the directory does not exist.`),
                    filePath: modulePath,
                });
            }
        }
        if (failures.length === 0) {
            findings.push({
                result: makeResult('AP-ARCH-005', 'error', true, 'All registered module paths exist as directories.'),
            });
        }
        else {
            findings.push(...failures);
        }
    }
    if (options.checkContractFileExists) {
        const failures = [];
        for (const [moduleName, moduleReference] of moduleEntries) {
            if (!moduleReference.contract) {
                continue;
            }
            const exists = await pathExists(toWorkspaceAbsolutePath(workspaceRoot, moduleReference.contract));
            if (!exists) {
                failures.push({
                    result: makeResult('AP-ARCH-006', 'error', false, `Module '${moduleName}' references contract ${moduleReference.contract} but the file does not exist.`),
                    filePath: moduleReference.contract,
                });
            }
        }
        if (failures.length === 0) {
            findings.push({
                result: makeResult('AP-ARCH-006', 'error', true, 'All registered module contract file references resolve to existing files.'),
            });
        }
        else {
            findings.push(...failures);
        }
    }
    if (options.checkContractIdentityMatchesRegistry) {
        const failures = [];
        for (const [moduleName, moduleReference] of moduleEntries) {
            if (!moduleReference.contract) {
                continue;
            }
            const contractPath = moduleReference.contract;
            const fullContractPath = toWorkspaceAbsolutePath(workspaceRoot, contractPath);
            if (!(await pathExists(fullContractPath))) {
                continue;
            }
            const parsedContract = await readModuleContract(workspaceRoot, contractPath);
            if ('error' in parsedContract) {
                failures.push({
                    result: makeResult('AP-ARCH-007', 'error', false, parsedContract.error),
                    filePath: contractPath,
                });
                continue;
            }
            const { contract: moduleContract } = parsedContract;
            if (moduleContract.module !== moduleName) {
                failures.push({
                    result: makeResult('AP-ARCH-007', 'error', false, `Module contract identity mismatch: registry key '${moduleName}' does not match contract.module '${String(moduleContract.module)}'.`),
                    filePath: contractPath,
                });
                continue;
            }
            if ((moduleContract.publicEntrypoints !== undefined &&
                normalizeStringArray(moduleContract.publicEntrypoints) === undefined) ||
                (moduleContract.dependsOn !== undefined &&
                    normalizeStringArray(moduleContract.dependsOn) === undefined) ||
                (moduleContract.ownedTables !== undefined &&
                    normalizeStringArray(moduleContract.ownedTables) === undefined) ||
                (moduleContract.exposedApis !== undefined &&
                    normalizeStringArray(moduleContract.exposedApis) === undefined)) {
                failures.push({
                    result: makeResult('AP-ARCH-007', 'error', false, `Module contract '${contractPath}' has malformed array fields. Expected arrays for publicEntrypoints, dependsOn, ownedTables, and exposedApis when present.`),
                    filePath: contractPath,
                });
            }
        }
        if (failures.length === 0) {
            findings.push({
                result: makeResult('AP-ARCH-007', 'error', true, 'All existing module contract files have identities and field shapes aligned with the module registry.'),
            });
        }
        else {
            findings.push(...failures);
        }
    }
    if (options.checkPublicEntrypointsAligned) {
        const failures = [];
        for (const [moduleName, moduleReference] of moduleEntries) {
            if (!moduleReference.contract) {
                continue;
            }
            const contractPath = moduleReference.contract;
            const fullContractPath = toWorkspaceAbsolutePath(workspaceRoot, contractPath);
            if (!(await pathExists(fullContractPath))) {
                continue;
            }
            const parsedContract = await readModuleContract(workspaceRoot, contractPath);
            if ('error' in parsedContract) {
                continue;
            }
            const registryEntrypoints = normalizeStringArray(moduleReference.publicEntrypoints);
            const contractEntrypoints = normalizeStringArray(parsedContract.contract.publicEntrypoints);
            if (!registryEntrypoints ||
                !contractEntrypoints ||
                !comparePublicEntrypoints(registryEntrypoints, contractEntrypoints)) {
                failures.push({
                    result: makeResult('AP-ARCH-008', 'error', false, `Public entrypoints for module '${moduleName}' are inconsistent between architecture.json and its contract file.`),
                    filePath: contractPath,
                });
            }
        }
        if (failures.length === 0) {
            findings.push({
                result: makeResult('AP-ARCH-008', 'error', true, 'All registered module public entrypoints are aligned with their module contract files.'),
            });
        }
        else {
            findings.push(...failures);
        }
    }
    return findings;
}
//# sourceMappingURL=moduleContractValidation.js.map