"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveChangedModulesFromFilesForTesting = resolveChangedModulesFromFilesForTesting;
exports.expandDependentsForTesting = expandDependentsForTesting;
exports.deriveAffectedDependentsForTesting = deriveAffectedDependentsForTesting;
exports.resolveChangedValidationScope = resolveChangedValidationScope;
const node_util_1 = require("node:util");
const node_child_process_1 = require("node:child_process");
const architectureMap_1 = require("../architectureMap");
const execFile = (0, node_util_1.promisify)(node_child_process_1.execFile);
function normalizePath(value) {
    return value.replace(/\\/g, '/');
}
function sortUnique(values) {
    return [...new Set(values)].sort((left, right) => left.localeCompare(right));
}
async function runGitNameOnly(workspaceRoot, args) {
    const { stdout } = await execFile('git', args, { cwd: workspaceRoot });
    return sortUnique(stdout
        .split(/\r?\n/)
        .map((line) => line.trim())
        .filter((line) => line.length > 0)
        .map((line) => normalizePath(line)));
}
async function detectChangedFilesForMode(workspaceRoot, mode, baseBranch) {
    if (mode === 'changed') {
        const [unstaged, staged] = await Promise.all([
            runGitNameOnly(workspaceRoot, ['diff', '--name-only']),
            runGitNameOnly(workspaceRoot, ['diff', '--name-only', '--cached']),
        ]);
        return sortUnique([...unstaged, ...staged]);
    }
    const [branchDiff, unstaged, staged] = await Promise.all([
        runGitNameOnly(workspaceRoot, ['diff', '--name-only', `${baseBranch}...HEAD`]),
        runGitNameOnly(workspaceRoot, ['diff', '--name-only']),
        runGitNameOnly(workspaceRoot, ['diff', '--name-only', '--cached']),
    ]);
    return sortUnique([...branchDiff, ...unstaged, ...staged]);
}
function resolveChangedModulesFromFiles(changedFiles, modulePaths, moduleContracts) {
    const sortedModules = [...modulePaths].sort((left, right) => {
        const lenCompare = right.sourcePath.length - left.sourcePath.length;
        if (lenCompare !== 0) {
            return lenCompare;
        }
        return left.moduleName.localeCompare(right.moduleName);
    });
    const resolved = new Set();
    for (const changedFile of changedFiles) {
        for (const moduleEntry of sortedModules) {
            const moduleRoot = normalizePath(moduleEntry.sourcePath);
            if (changedFile === moduleRoot || changedFile.startsWith(`${moduleRoot}/`)) {
                resolved.add(moduleEntry.moduleName);
                break;
            }
        }
        for (const contractEntry of moduleContracts ?? []) {
            const contractPath = normalizePath(contractEntry.contractPath ?? '');
            if (contractPath.length === 0) {
                continue;
            }
            if (changedFile === contractPath) {
                resolved.add(contractEntry.moduleName);
                break;
            }
        }
    }
    return sortUnique(resolved);
}
function expandDependents(mapEdges, directModules) {
    const inbound = new Map();
    for (const edge of mapEdges) {
        const existing = inbound.get(edge.target) ?? new Set();
        existing.add(edge.source);
        inbound.set(edge.target, existing);
    }
    const visited = new Set(directModules);
    const queue = [...directModules];
    while (queue.length > 0) {
        const current = queue.shift();
        if (!current) {
            continue;
        }
        for (const dependent of inbound.get(current) ?? new Set()) {
            if (visited.has(dependent)) {
                continue;
            }
            visited.add(dependent);
            queue.push(dependent);
        }
    }
    return sortUnique(visited);
}
function deriveAffectedDependents(directModules, affectedModules) {
    const directSet = new Set(directModules);
    return sortUnique(affectedModules.filter((moduleName) => !directSet.has(moduleName)));
}
function deriveDirectDependents(mapEdges, directModules) {
    const directSet = new Set(directModules);
    const directDependents = new Set();
    for (const edge of mapEdges) {
        if (directSet.has(edge.target) && !directSet.has(edge.source)) {
            directDependents.add(edge.source);
        }
    }
    return sortUnique(directDependents);
}
function deriveTransitiveDependents(directDependents, affectedDependents) {
    const directSet = new Set(directDependents);
    return sortUnique(affectedDependents.filter((moduleName) => !directSet.has(moduleName)));
}
function resolveChangedModulesFromFilesForTesting(changedFiles, modulePaths, moduleContracts) {
    return resolveChangedModulesFromFiles(changedFiles, modulePaths, moduleContracts);
}
function expandDependentsForTesting(mapEdges, directModules) {
    return expandDependents(mapEdges, directModules);
}
function deriveAffectedDependentsForTesting(directModules, affectedModules) {
    return deriveAffectedDependents(directModules, affectedModules);
}
async function resolveChangedValidationScope(workspaceRoot, options) {
    const baseBranch = options.baseBranch?.trim() || 'main';
    try {
        const changedFiles = await detectChangedFilesForMode(workspaceRoot, options.mode, baseBranch);
        const map = await (0, architectureMap_1.generateArchitectureMap)(workspaceRoot);
        const directModules = resolveChangedModulesFromFiles(changedFiles, map.modules.map((moduleEntry) => ({
            moduleName: moduleEntry.moduleName,
            sourcePath: normalizePath(moduleEntry.sourcePath),
        })), map.modules.map((moduleEntry) => ({
            moduleName: moduleEntry.moduleName,
            contractPath: moduleEntry.contractPath,
        })));
        const affectedModules = expandDependents(map.edges.map((edge) => ({ source: edge.source, target: edge.target })), directModules);
        const affectedDependents = deriveAffectedDependents(directModules, affectedModules);
        const mapEdges = map.edges.map((edge) => ({ source: edge.source, target: edge.target }));
        const directDependents = deriveDirectDependents(mapEdges, directModules);
        return {
            mode: options.mode,
            baseBranch,
            gitAvailable: true,
            changedFiles,
            directModules,
            affectedModules,
            affectedDependents,
            directDependents,
            transitiveDependents: deriveTransitiveDependents(directDependents, affectedDependents),
        };
    }
    catch (error) {
        const message = error instanceof Error ? error.message : 'Unable to detect changed files.';
        return {
            mode: options.mode,
            baseBranch,
            gitAvailable: false,
            changedFiles: [],
            directModules: [],
            affectedModules: [],
            affectedDependents: [],
            directDependents: [],
            transitiveDependents: [],
            message,
        };
    }
}
//# sourceMappingURL=changedFilesResolver.js.map