/**
 * Main Path Integration Contract — 核心扫描（模块导入扫描 + 可达性追踪 + 集成测试发现 + 契约构建）
 */
import fs from "node:fs";
import fspath from "node:path";
import { debug } from "../../core/logger.js";
import { PRODUCTION_EXTENSIONS } from "./constants.js";
import { createEntryPointTrace } from "./factories.js";
import { isProductionFile, walkDir, extractImportPaths, resolveImportPath, normalizeModulePath, computeJavaFqn, matchJavaFqn, computePythonModulePath, computeGoPkgPath, extractImportedNames, extractJavaImportedNames, extractGoImportedNames, extractPythonImportedNames, detectTsCallEvidence, detectJavaCallEvidence, detectPythonCallEvidence, detectGoCallEvidence, isOnlyReExport, isRegistryOnlyImport, } from "./scanning_infra.js";
import { errorMessage } from "../../core/helpers.js";
export { isProductionFile, walkDir, extractImportPaths, resolveImportPath, computeJavaFqn } from "./scanning_infra.js";
export function scanModuleImporters(projectPath, moduleRelPath) {
    debug("主链路接入", "扫描模块导入者 — " + moduleRelPath);
    const result = {
        production_imports: [],
        production_calls: [],
        test_imports: [],
        barrel_exports: [],
        registry_declarations: [],
        import_only: [],
    };
    const targetNorm = normalizeModulePath(moduleRelPath);
    const moduleExt = fspath.extname(moduleRelPath);
    const allFiles = walkDir(projectPath);
    let targetJavaFqn = null;
    if (moduleExt === ".java" || moduleExt === ".kt") {
        targetJavaFqn = computeJavaFqn(moduleRelPath, projectPath);
    }
    let targetPyModule = null;
    if (moduleExt === ".py") {
        targetPyModule = computePythonModulePath(moduleRelPath);
    }
    let targetGoPkg = null;
    if (moduleExt === ".go") {
        targetGoPkg = computeGoPkgPath(moduleRelPath);
    }
    for (const file of allFiles) {
        const rel = fspath.relative(projectPath, file).replace(/\\/g, "/");
        if (normalizeModulePath(rel) === targetNorm)
            continue;
        const ext = fspath.extname(file);
        if (![".ts", ".tsx", ".js", ".jsx", ".java", ".kt", ".go", ".py"].includes(ext))
            continue;
        let content;
        try {
            content = fs.readFileSync(file, "utf-8");
        }
        catch {
            continue;
        }
        let matched = false;
        let importedNames = [];
        if (moduleExt === ".java" || moduleExt === ".kt") {
            if (targetJavaFqn && matchJavaFqn(content, targetJavaFqn)) {
                matched = true;
                importedNames = extractJavaImportedNames(content, targetJavaFqn);
            }
        }
        else if (moduleExt === ".py") {
            if (targetPyModule) {
                const importerPaths = extractImportPaths(content, rel);
                for (const imp of importerPaths) {
                    if (imp === targetPyModule || imp.startsWith(targetPyModule + ".")) {
                        matched = true;
                        importedNames = extractPythonImportedNames(content, targetPyModule);
                        break;
                    }
                }
            }
        }
        else if (moduleExt === ".go") {
            if (targetGoPkg) {
                const importerPaths = extractImportPaths(content, rel);
                for (const imp of importerPaths) {
                    if (imp.endsWith(targetGoPkg) || imp === targetGoPkg) {
                        matched = true;
                        importedNames = extractGoImportedNames(content, targetGoPkg);
                        break;
                    }
                }
            }
        }
        else {
            const imports = extractImportPaths(content, rel);
            for (const imp of imports) {
                if (!imp.startsWith("."))
                    continue;
                const resolved = resolveImportPath(imp, rel, projectPath);
                if (resolved && normalizeModulePath(resolved) === targetNorm) {
                    matched = true;
                    importedNames = extractImportedNames(content, targetNorm);
                    break;
                }
            }
        }
        if (!matched)
            continue;
        const isTest = /\.test\.|\.spec\.|\/tests\/|\/__tests__\//.test(rel);
        if (isTest) {
            result.test_imports.push(rel);
            continue;
        }
        if (isOnlyReExport(content, targetNorm, ext)) {
            result.barrel_exports.push(rel);
            continue;
        }
        if (isRegistryOnlyImport(content, targetNorm, ext)) {
            result.registry_declarations.push(rel);
            continue;
        }
        let callEvidence = [];
        if (ext === ".java" || ext === ".kt") {
            callEvidence = detectJavaCallEvidence(content, importedNames);
        }
        else if (ext === ".py") {
            callEvidence = detectPythonCallEvidence(content, importedNames);
        }
        else if (ext === ".go") {
            callEvidence = detectGoCallEvidence(content, importedNames);
        }
        else {
            callEvidence = detectTsCallEvidence(content, importedNames);
        }
        if (callEvidence.length > 0) {
            result.production_imports.push(rel);
            result.production_calls.push({ importer: rel, patterns: callEvidence });
        }
        else {
            result.import_only.push(rel);
        }
    }
    debug("主链路接入", "扫描模块导入者完成 — " + moduleRelPath + " 生产导入 " + result.production_imports.length + " 测试导入 " + result.test_imports.length + " 调用证据 " + result.production_calls.length);
    return result;
}
export function identifyProjectEntryPoints(projectPath) {
    debug("主链路接入", "识别项目入口点 — " + projectPath);
    const eps = [];
    const allFiles = walkDir(projectPath);
    const patterns = [
        { test: /(?:adapters|server)\/.*tools?(?:\/index)?\.ts$/, type: "mcp_tool", example: "MCP tool handler" },
        { test: /\/bin\//, type: "cli", example: "CLI command" },
        { test: /\/cli\//, type: "cli", example: "CLI entry" },
        { test: /\/commands?\//, type: "command", example: "Command handler" },
        { test: /\/routes?\//, type: "backend_route", example: "HTTP route" },
        { test: /\/controllers?\//, type: "backend_route", example: "Controller" },
        { test: /\/api\//, type: "public_api", example: "API endpoint" },
        { test: /\/pages?\//, type: "frontend_route", example: "Page component" },
        { test: /\/app\//, type: "frontend_route", example: "App entry" },
        { test: /\/jobs?\//, type: "job", example: "Background job" },
        { test: /\/consumers?\//, type: "consumer", example: "Event consumer" },
        { test: /\/workers?\//, type: "job", example: "Worker" },
        { test: /\/crons?\//, type: "cron", example: "Cron job" },
        { test: /\/webhooks?\//, type: "webhook", example: "Webhook handler" },
    ];
    for (const file of allFiles) {
        const rel = fspath.relative(projectPath, file).replace(/\\/g, "/");
        const ext = fspath.extname(file);
        if (!PRODUCTION_EXTENSIONS.has(ext))
            continue;
        if (/\.test\.|\.spec\.|\.d\.ts/.test(rel))
            continue;
        if (!fs.existsSync(file))
            continue;
        for (const { test, type, example } of patterns) {
            if (test.test(rel)) {
                eps.push(createEntryPointTrace({
                    entry_type: type,
                    entry_id: rel,
                    call_chain: [rel],
                    trigger_example: example,
                }));
                break;
            }
        }
    }
    debug("主链路接入", "识别项目入口点完成 — 共 " + eps.length + " 个入口");
    return eps;
}
export function traceModuleReachability(projectPath, moduleRelPath, entryPoints) {
    debug("主链路接入", "追踪模块可达性 — " + moduleRelPath + " 从 " + entryPoints.length + " 个入口");
    const targetNorm = normalizeModulePath(moduleRelPath);
    const moduleExt = fspath.extname(moduleRelPath);
    const reachable = [];
    let targetJavaFqn = null;
    if (moduleExt === ".java" || moduleExt === ".kt") {
        targetJavaFqn = computeJavaFqn(moduleRelPath, projectPath);
    }
    let targetPyModule = null;
    if (moduleExt === ".py") {
        targetPyModule = computePythonModulePath(moduleRelPath);
    }
    let targetGoPkg = null;
    if (moduleExt === ".go") {
        targetGoPkg = computeGoPkgPath(moduleRelPath);
    }
    for (const ep of entryPoints) {
        const epFile = fspath.resolve(projectPath, ep.entry_id);
        if (!fs.existsSync(epFile))
            continue;
        const chain = [];
        const visited = new Set();
        if (dfsTrace(epFile, targetNorm, projectPath, visited, chain, targetJavaFqn, targetPyModule, targetGoPkg)) {
            reachable.push({
                ...ep,
                call_chain: [ep.entry_id, ...chain],
            });
        }
    }
    debug("主链路接入", "追踪模块可达性完成 — " + moduleRelPath + " 可达 " + reachable.length + " 个入口");
    return reachable;
}
function dfsTrace(currentFile, targetNorm, projectPath, visited, chain, targetJavaFqn, targetPyModule, targetGoPkg, depth = 0) {
    if (depth > 15)
        return false;
    const abs = fspath.resolve(currentFile);
    if (visited.has(abs))
        return false;
    visited.add(abs);
    let content;
    try {
        content = fs.readFileSync(abs, "utf-8");
    }
    catch {
        return false;
    }
    const rel = fspath.relative(projectPath, abs).replace(/\\/g, "/");
    const ext = fspath.extname(rel);
    if (targetJavaFqn && (ext === ".java" || ext === ".kt")) {
        if (matchJavaFqn(content, targetJavaFqn)) {
            if (depth > 0)
                chain.push(rel);
            return true;
        }
    }
    else if (targetPyModule && ext === ".py") {
        const importerPaths = extractImportPaths(content, rel);
        for (const imp of importerPaths) {
            if (imp === targetPyModule || imp.startsWith(targetPyModule + ".")) {
                if (depth > 0)
                    chain.push(rel);
                return true;
            }
        }
    }
    else if (targetGoPkg && ext === ".go") {
        const importerPaths = extractImportPaths(content, rel);
        for (const imp of importerPaths) {
            if (imp.endsWith(targetGoPkg) || imp === targetGoPkg) {
                if (depth > 0)
                    chain.push(rel);
                return true;
            }
        }
    }
    else {
        const imports = extractImportPaths(content, rel);
        for (const imp of imports) {
            if (!imp.startsWith("."))
                continue;
            const resolved = resolveImportPath(imp, rel, projectPath);
            if (resolved && normalizeModulePath(resolved) === targetNorm) {
                chain.push(resolved);
                return true;
            }
        }
    }
    if (!targetJavaFqn && !targetPyModule && !targetGoPkg) {
        const imports = extractImportPaths(content, rel);
        for (const imp of imports) {
            if (!imp.startsWith("."))
                continue;
            const resolved = resolveImportPath(imp, rel, projectPath);
            if (!resolved)
                continue;
            const nextAbs = fspath.resolve(projectPath, resolved);
            if (dfsTrace(nextAbs, targetNorm, projectPath, visited, chain, null, null, null, depth + 1)) {
                chain.unshift(resolved);
                return true;
            }
        }
    }
    return false;
}
function stripComments(source) {
    let s = source.replace(/\/\/.*$/gm, "");
    s = s.replace(/\/\*[\s\S]*?\*\//g, "");
    return s;
}
export function collectModuleObservability(projectPath, moduleRelPath) {
    debug("主链路接入", "收集模块可观测性 — " + moduleRelPath);
    const refs = [];
    const fullPath = fspath.join(projectPath, moduleRelPath);
    let content;
    try {
        content = fs.readFileSync(fullPath, "utf-8");
    }
    catch (e) {
        debug("主链路接入", "收集模块可观测性失败 — " + moduleRelPath + ": " + (errorMessage(e)));
        return refs;
    }
    const patterns = [
        { re: /VerifyResult|TaskContext|GovernanceReport|DeliveryResult/, desc: "结果类型引用" },
        { re: /main_path_integration/, desc: "main_path_integration 字段" },
        { re: /summary\s*[:+=]/, desc: "summary 生成" },
        { re: /console\.|logger\.|log\(/, desc: "日志输出" },
    ];
    for (const { re, desc } of patterns) {
        if (re.test(content))
            refs.push(`${moduleRelPath}: ${desc}`);
    }
    const modBasename = fspath.basename(moduleRelPath, fspath.extname(moduleRelPath));
    const allFiles = walkDir(projectPath);
    for (const file of allFiles) {
        const rel = fspath.relative(projectPath, file).replace(/\\/g, "/");
        if (normalizeModulePath(rel) === normalizeModulePath(moduleRelPath))
            continue;
        if (/\.test\.|\.spec\.|\/tests\//.test(rel))
            continue;
        try {
            const fc = fs.readFileSync(file, "utf-8");
            if (fc.includes(modBasename) && /result|response|output|report|evidence/.test(fc)) {
                refs.push(`referenced in ${rel}`);
            }
        }
        catch {
            continue;
        }
    }
    debug("主链路接入", "收集模块可观测性完成 — " + moduleRelPath + " 共 " + refs.length + " 条证据");
    return refs;
}
export function findIntegrationTests(projectPath, moduleRelPath) {
    debug("主链路接入", "查找集成测试 — " + moduleRelPath);
    const tests = [];
    const allFiles = walkDir(projectPath);
    const normalized = moduleRelPath.replace(/\\/g, "/");
    const entryPoints = identifyProjectEntryPoints(projectPath);
    for (const file of allFiles) {
        const rel = fspath.relative(projectPath, file).replace(/\\/g, "/");
        if (!/\.test\.|\.spec\.|\/tests?\/|[Tt]est\.(?:ts|tsx|js|jsx|java|kt)|(?:integration|contract)[._-]/i.test(rel))
            continue;
        let content;
        try {
            content = fs.readFileSync(file, "utf-8");
        }
        catch {
            continue;
        }
        const ext = fspath.extname(rel);
        const codeOnly = stripComments(content);
        if (ext === ".java" || ext === ".kt") {
            const targetFqn = computeJavaFqn(normalized, projectPath);
            if (!targetFqn)
                continue;
            if (!matchJavaFqn(codeOnly, targetFqn))
                continue;
            const importedNames = extractJavaImportedNames(codeOnly, targetFqn);
            if (importedNames.length === 0)
                continue;
            const callEvidence = detectJavaCallEvidence(codeOnly, importedNames);
            if (callEvidence.length > 0)
                tests.push(rel);
        }
        else if (ext === ".py") {
            const targetPyModule = computePythonModulePath(normalized);
            const imports = extractImportPaths(codeOnly, rel);
            const hasImport = imports.some((imp) => imp === targetPyModule || imp.endsWith("." + targetPyModule.split(".").pop()));
            if (!hasImport)
                continue;
            const names = extractPythonImportedNames(codeOnly, targetPyModule);
            const callEvidence = detectPythonCallEvidence(codeOnly, names);
            if (callEvidence.length > 0)
                tests.push(rel);
        }
        else {
            const testImports = extractImportPaths(codeOnly, rel);
            let isIntegrationTest = false;
            for (const imp of testImports) {
                if (!imp.startsWith("."))
                    continue;
                const resolved = resolveImportPath(imp, rel, projectPath);
                if (!resolved)
                    continue;
                const epMatch = entryPoints.find((ep) => ep.entry_id === resolved);
                if (epMatch) {
                    const traces = traceModuleReachability(projectPath, normalized, [epMatch]);
                    if (traces.length > 0) {
                        isIntegrationTest = true;
                        break;
                    }
                }
            }
            if (isIntegrationTest) {
                tests.push(rel);
                continue;
            }
            const importedNames = extractImportedNames(codeOnly, normalized);
            if (importedNames.length === 0)
                continue;
            const callEvidence = detectTsCallEvidence(codeOnly, importedNames);
            if (callEvidence.length > 0)
                tests.push(rel);
        }
    }
    debug("主链路接入", "查找集成测试完成 — " + moduleRelPath + " 共 " + tests.length + " 个测试");
    return tests;
}
export function buildMainPathIntegrationContracts(projectPath, changedFiles, config) {
    const contracts = [];
    debug("主链路接入", `开始扫描变更文件 — 共 ${changedFiles.length} 个文件`);
    const entryPoints = identifyProjectEntryPoints(projectPath);
    for (const filePath of changedFiles) {
        const normalized = filePath.replace(/\\/g, "/");
        const prodCheck = isProductionFile(normalized, config);
        if (!prodCheck.isProd)
            continue;
        debug("主链路接入", "扫描生产文件 — " + normalized);
        const fullPath = fspath.join(projectPath, normalized);
        if (!fs.existsSync(fullPath)) {
            debug("主链路接入", "文件不存在 — " + normalized);
            continue;
        }
        const scanResult = scanModuleImporters(projectPath, normalized);
        const entryTraces = traceModuleReachability(projectPath, normalized, entryPoints);
        const hasCallEvidence = scanResult.production_imports.length > 0;
        const hasEntryTraceLocal = entryTraces.length > 0;
        let status;
        if (hasCallEvidence && hasEntryTraceLocal) {
            status = "integrated";
        }
        else if (hasCallEvidence && !hasEntryTraceLocal) {
            status = "implemented_not_integrated";
        }
        else if (scanResult.import_only.length > 0) {
            status = "implemented_not_integrated";
        }
        else if (scanResult.barrel_exports.length > 0 || scanResult.registry_declarations.length > 0) {
            status = "implemented_not_integrated";
        }
        else if (scanResult.test_imports.length > 0) {
            status = "implemented_not_integrated";
        }
        else {
            status = "implemented_not_integrated";
        }
        debug("主链路接入", "状态判定 — " + normalized + " → " + status);
        const observabilityRefs = collectModuleObservability(projectPath, normalized);
        const intTests = findIntegrationTests(projectPath, normalized);
        contracts.push({
            module_path: normalized,
            status,
            production_imports: scanResult.production_imports,
            entry_traces: entryTraces,
            observability_refs: observabilityRefs,
            integration_tests: intTests,
            owner: "",
        });
    }
    debug("主链路接入", "扫描变更文件完成 — 共 " + contracts.length + " 个契约");
    return contracts;
}
export function collectAllProductionFiles(projectPath, config) {
    debug("主链路接入", "收集所有生产文件 — " + projectPath);
    const files = [];
    const allFiles = walkDir(projectPath);
    for (const file of allFiles) {
        const rel = fspath.relative(projectPath, file).replace(/\\/g, "/");
        const prodCheck = isProductionFile(rel, config);
        if (prodCheck.isProd) {
            files.push(rel);
        }
    }
    debug("主链路接入", "收集所有生产文件完成 — 共 " + files.length + " 个文件");
    return files;
}
//# sourceMappingURL=scanning.js.map