/**
 * Phase 3 — 主链路真实消费检查。
 */
import fs from "node:fs";
import path from "node:path";
import { safeReadCached } from "./helpers.js";
import { sourceImportsModule, sourceContainsIdentifier } from "../../source_code_matcher.js";
/** 已知的消费者入口→文件映射 */
const CONSUMER_ENTRY_FILES = {
    "CLI validate": ["src/bin/soloforge.ts", "src/bin/commands/validate.ts"],
    "CLI sync-templates": ["src/bin/soloforge.ts", "src/bin/commands/sync.ts"],
    "CLI sync-adapters": ["src/bin/soloforge.ts", "src/bin/commands/sync.ts"],
    "CLI migrate": ["src/bin/soloforge.ts", "src/bin/commands/sync.ts"],
    "CLI validate-knowledge": ["src/engine/knowledge/knowledge_scenario_registry.ts"],
    "联调验证(验证)": ["src/engine/release/verifier.ts"],
    "联调验证(交付)": ["src/server/tools/index.ts", "src/engine/audit/delivery_readiness.ts"],
    "架构设计": ["src/server/tools/index.ts", "src/engine/pipeline/intent_expander.ts", "src/server/tools/gate_checks.ts", "src/server/tools/lazy_loaders.ts", "src/server/tools/cep_assessment.ts"],
    "问题管理流程": ["src/bin/commands/sync.ts"],
    "sf_expand": ["src/server/tools/index.ts", "src/engine/pipeline/intent_expander.ts", "src/server/tools/gate_checks.ts", "src/server/tools/lazy_loaders.ts", "src/server/tools/cep_assessment.ts"],
    "CLI validate-new-issue": ["src/bin/soloforge.ts", "src/bin/commands/sync.ts"],
};
/** 模块名→文件路径映射 (用于模块间调用链如 "knowledge_evolution.validateCandidateTrust") */
const MODULE_FILE_MAP = {
    "knowledge_lifecycle": "src/engine/knowledge/knowledge_lifecycle.ts",
    "knowledge_evolution": "src/engine/knowledge/knowledge_evolution.ts",
    "chinese_semantic_priority": "src/engine/knowledge/chinese_semantic_priority.ts",
    "language_policy": "src/engine/knowledge/language_policy.ts",
    "documentation_governance": "src/engine/knowledge/documentation_governance.ts",
    "template_sync": "src/engine/templates/template_sync.ts",
    "user_promise": "src/engine/contracts/user_promise.ts",
    "adapter_prompt_contract": "src/engine/adapter_prompt_contract.ts",
    "release_compatibility": "src/engine/knowledge/release_compatibility.ts",
    "extension_contract": "src/engine/contracts/extension_contract.ts",
    "platform_context": "src/engine/contracts/platform_context.ts",
    "metric_governance": "src/engine/contracts/metric_governance.ts",
    "technology_decision": "src/engine/contracts/technology_decision.ts",
    "brainstorm_contract": "src/engine/contracts/brainstorm_contract.ts",
    "detail_discipline": "src/engine/contracts/detail_discipline.ts",
    "first_principles": "src/engine/contracts/first_principles.ts",
    "architecture_design_contract": "src/engine/contracts/architecture_design_contract.ts",
    "existing_system_analysis": "src/engine/contracts/existing_system_analysis.ts",
    "coding_readiness_gate": "src/engine/contracts/coding_readiness_gate.ts",
    "local_docker_acceptance": "src/engine/contracts/local_docker_acceptance.ts",
    "workflow_template_pack": "src/engine/contracts/workflow_template_pack.ts",
    "evolution_regression_gate": "src/engine/contracts/evolution_regression_gate.ts",
    "delivery_readiness": "src/engine/audit/delivery_readiness.ts",
    "knowledge_scenario_registry": "src/engine/knowledge/knowledge_scenario_registry.ts",
    "intent_expander": "src/engine/pipeline/intent_expander.ts",
    "gate_checks": "src/server/tools/gate_checks.ts",
};
/** cmdXxx → 实际命令文件映射 */
const CMD_FILE_MAP = {
    "cmdValidate": "src/bin/commands/validate.ts",
    "cmdSyncTemplates": "src/bin/commands/sync.ts",
    "cmdSyncAdapters": "src/bin/commands/sync.ts",
    "cmdMigrate": "src/bin/commands/sync.ts",
    "cmdValidateNewIssue": "src/bin/commands/sync.ts",
};
/** 从调用链文本中解析出所有消费者文件 */
function resolveConsumerFiles(chainText) {
    const files = new Set();
    const segments = chainText.split("→").map(s => s.trim()).filter(Boolean);
    for (const seg of segments) {
        // 检查是否匹配已知入口 (如 "CLI validate →" 或 "sf_verify →")
        for (const [entry, paths] of Object.entries(CONSUMER_ENTRY_FILES)) {
            if (seg.includes(entry) || seg.startsWith(entry)) {
                for (const p of paths)
                    files.add(p);
            }
        }
        // 检查是否匹配 cmdXxx 命令 (如 "cmdValidate")
        const cmdMatch = seg.match(/cmd([A-Z]\w+)/);
        if (cmdMatch) {
            files.add("src/bin/soloforge.ts");
            const cmdFile = CMD_FILE_MAP[cmdMatch[0]];
            if (cmdFile)
                files.add(cmdFile);
        }
        // 检查是否匹配 generateVerifyCommands
        if (seg.includes("generateVerifyCommands")) {
            files.add("src/engine/release/verifier.ts");
        }
        // 检查是否匹配 evaluateDeliveryReadiness
        if (seg.includes("evaluateDeliveryReadiness")) {
            files.add("src/engine/audit/delivery_readiness.ts");
            files.add("src/server/tools/index.ts");
        }
        // 检查是否匹配 checkArchitectureDesignGate
        if (seg.includes("checkArchitectureDesignGate")) {
            files.add("src/server/tools/gate_checks.ts");
        }
        // 检查模块.function 模式 (如 "knowledge_evolution.validateCandidateTrust")
        for (const [modName, modPath] of Object.entries(MODULE_FILE_MAP)) {
            if (seg.includes(`${modName}.`) || seg.includes(modName)) {
                files.add(modPath);
            }
        }
        // 检查 buildTemplateManifestFromSource
        if (seg.includes("buildTemplateManifestFromSource")) {
            files.add("src/bin/soloforge.ts");
        }
    }
    return [...files];
}
/** 从字符串数组格式的字段中提取文件路径列表 */
function extractStringArray(rawValue) {
    // 处理 ["a", "b"] 格式
    const items = rawValue.match(/["']([^"']+)["']/g) ?? [];
    return items.map(s => s.replace(/["']/g, ""));
}
/** 从注册表文件内容中提取所有验收条目的结构化数据 */
function parseAcceptanceEntries(content) {
    const entries = [];
    const lines = content.split("\n");
    let currentEntry = null;
    for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        // 检测新条目开始 (issue_id 出现)
        const issueMatch = line.match(/issue_id:\s*["']([^"']+)["']/);
        if (issueMatch) {
            if (currentEntry)
                entries.push(currentEntry);
            currentEntry = {
                issue_id: issueMatch[1],
                owner_files: [],
                required_entrypoints: [],
                mainline_consumption_check: "",
                entryStartLine: i,
            };
            continue;
        }
        if (!currentEntry)
            continue;
        // 提取 owner_files
        if (line.includes("owner_files:") && !line.includes("//")) {
            // 可能是单行或多行
            let raw = line;
            if (!raw.includes("]")) {
                let j = i + 1;
                while (j < lines.length && !raw.includes("]")) {
                    raw += lines[j];
                    j++;
                }
            }
            currentEntry.owner_files = extractStringArray(raw.replace(/^.*owner_files:\s*/, ""));
        }
        // 提取 required_entrypoints
        if (line.includes("required_entrypoints:") && !line.includes("//")) {
            let raw = line;
            if (!raw.includes("]")) {
                let j = i + 1;
                while (j < lines.length && !raw.includes("]")) {
                    raw += lines[j];
                    j++;
                }
            }
            currentEntry.required_entrypoints = extractStringArray(raw.replace(/^.*required_entrypoints:\s*/, ""));
        }
        // 提取 mainline_consumption_check
        if (line.includes("mainline_consumption_check:") && !line.includes("//")) {
            let raw = line;
            if (!raw.includes("]")) {
                let j = i + 1;
                while (j < lines.length && !raw.includes("]")) {
                    raw += lines[j];
                    j++;
                }
            }
            currentEntry.mainline_consumption_check = raw.replace(/^.*mainline_consumption_check:\s*/, "");
        }
    }
    if (currentEntry)
        entries.push(currentEntry);
    return entries;
}
export async function check(ctx, hardFail, info) {
    const rootDir = ctx.rootDir;
    const registryFiles = [
        { filePath: "tests/engine/extension_acceptance_registry.ts", label: "Extension 验收" },
        { filePath: "src/engine/knowledge/knowledge_acceptance_registry.ts", label: "知识验收" },
    ];
    for (const reg of registryFiles) {
        const content = safeReadCached(path.join(rootDir, reg.filePath), ctx.readCache);
        if (!content) {
            info?.(`  [跳过] ${reg.filePath} 不存在`);
            continue;
        }
        const entries = parseAcceptanceEntries(content);
        for (const entry of entries) {
            // ── 检查 1: owner_files 必须在磁盘上存在 ──
            for (const ownerFile of entry.owner_files) {
                const fullPath = path.join(rootDir, ownerFile);
                if (!fs.existsSync(fullPath)) {
                    hardFail("MAINLINE_OWNER_FILE_MISSING", `${reg.label}: ${entry.issue_id} 的 owner_file "${ownerFile}" 不存在`, [reg.filePath, ownerFile], entry.issue_id, "旧 gate 不校验 owner_files 是否真实存在", "创建缺失文件或修正 owner_files");
                }
            }
            // ── 检查 2: required_entrypoints 必须在 owner_files 中真实 export ──
            for (const ep of entry.required_entrypoints) {
                let found = false;
                for (const ownerFile of entry.owner_files) {
                    const srcContent = safeReadCached(path.join(rootDir, ownerFile), ctx.readCache);
                    if (!srcContent)
                        continue;
                    // 检查 export function 或 export const 或 export async function
                    const exportPattern = new RegExp(`export\\s+(async\\s+)?function\\s+${ep}\\b|export\\s+const\\s+${ep}\\b`);
                    if (exportPattern.test(srcContent)) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    hardFail("MAINLINE_ENTRYPOINT_NOT_EXPORTED", `${reg.label}: ${entry.issue_id} 的 required_entrypoint "${ep}" 未在 owner_files 中找到 export`, [reg.filePath, ...entry.owner_files], entry.issue_id, "旧 gate 不校验 required_entrypoints 是否真实导出", "添加缺失的 export 或修正 required_entrypoints");
                }
            }
            // ── 检查 3: 调用链格式 — pending_integration 或至少 2 级 (→ 分隔) ──
            const chainText = entry.mainline_consumption_check.match(/\[([^\]]+)\]/)?.[1] || "";
            const isPendingIntegration = chainText.includes("pending_integration");
            const chainSegments = chainText.split("→").map(s => s.trim()).filter(Boolean);
            if (isPendingIntegration) {
                // 诚实标记: 入口已 export 但无生产消费者 — hard_fail 提醒集成未完成
                hardFail("MAINLINE_PENDING_INTEGRATION", `${reg.label}: ${entry.issue_id} 标记为 pending_integration: ${chainText.replace("pending_integration: ", "")}`, [reg.filePath], entry.issue_id, "入口函数已实现但无真实生产消费路径", "补充消费者源码调用");
                continue;
            }
            if (chainSegments.length < 2) {
                hardFail("MAINLINE_CHAIN_TOO_SHORT", `${reg.label}: ${entry.issue_id} 的 mainline_consumption_check 调用链不足 2 级: "${chainText}"`, [reg.filePath], entry.issue_id, "调用链必须包含入口→调用→效果至少 2 级", "补充调用链");
                continue;
            }
            // ── 检查 4: 调用链中声称的消费者必须真实 import/call required_entrypoints ──
            const consumerFiles = resolveConsumerFiles(chainText);
            if (consumerFiles.length === 0) {
                // 调用链中的入口无法映射到任何消费者文件
                hardFail("MAINLINE_CONSUMER_NOT_FOUND", `${reg.label}: ${entry.issue_id} 的调用链入口无法映射到已知消费者文件: "${chainSegments[0]}"`, [reg.filePath], entry.issue_id, "调用链声称的入口没有对应的消费者文件", "补充消费源码或修正调用链描述");
                continue;
            }
            // 对每个 required_entrypoint，验证至少有一条真实消费路径
            // 路径 A: 消费者文件直接 import + call 该 entrypoint
            // 路径 B: entrypoint 在 owner_file 内部被同一模块的另一个已消费函数调用 (传递消费)
            //         条件: 消费者 import 了 owner_file 的某个函数 + entrypoint 在 owner_file 内被调用
            for (const ep of entry.required_entrypoints) {
                let consumedByRealCode = false;
                // 路径 A: 直接消费
                for (const consumerFile of consumerFiles) {
                    const consumerContent = safeReadCached(path.join(rootDir, consumerFile), ctx.readCache);
                    if (!consumerContent)
                        continue;
                    const staticImportPattern = new RegExp(`import\\s+\\{[^}]*\\b${ep}\\b[^}]*\\}\\s+from`);
                    const dynamicImportPattern = new RegExp(`\\{[^}]*\\b${ep}\\b[^}]*\\}\\s*=\\s*await\\s+import\\(`);
                    const hasLazyModuleImport = entry.owner_files.some((ownerFile) => {
                        const moduleName = path.basename(ownerFile, ".ts");
                        // 同时计算从各消费方位置到所属模块的相对路径
                        const ownerRelFromEngine = ownerFile.replace(/^src\/engine\//, "").replace(/\.ts$/, ".js");
                        return sourceImportsModule(consumerContent, `../../engine/${moduleName}.js`)
                            || sourceImportsModule(consumerContent, `../engine/${moduleName}.js`)
                            || sourceImportsModule(consumerContent, `./${moduleName}.js`)
                            || sourceImportsModule(consumerContent, `../../engine/${ownerRelFromEngine}`)
                            || sourceImportsModule(consumerContent, `../engine/${ownerRelFromEngine}`)
                            || sourceImportsModule(consumerContent, `./engine/${ownerRelFromEngine}`);
                    });
                    const hasImport = staticImportPattern.test(consumerContent)
                        || dynamicImportPattern.test(consumerContent)
                        || hasLazyModuleImport;
                    if (!hasImport)
                        continue;
                    const importLinePattern = new RegExp(`import\\s+\\{[^}]*\\b${ep}\\b|\\{[^}]*\\b${ep}\\b[^}]*\\}\\s*=\\s*await\\s+import`);
                    const callLines = consumerContent.split("\n").filter(l => !importLinePattern.test(l) && l.includes(ep));
                    if (callLines.length > 0) {
                        consumedByRealCode = true;
                        break;
                    }
                }
                // 路径 B: 传递消费 — entrypoint 在 owner_file 内部被另一个函数调用
                // 且消费者 import 了 owner_file 中的某个函数
                // 路径 C: 跨文件消费 — 调用在 consumerFile_A，import 在 consumerFile_B（如 lazy loader）
                //         条件: 至少一个 consumer 有 entrypoint 调用行 + 至少一个 consumer imports owner module
                if (!consumedByRealCode) {
                    // 路径 C 先检查
                    let anyConsumerHasCall = false;
                    let anyConsumerImportsModule = false;
                    for (const consumerFile of consumerFiles) {
                        const consumerContent = safeReadCached(path.join(rootDir, consumerFile), ctx.readCache);
                        if (!consumerContent)
                            continue;
                        const importLinePattern = new RegExp(`import\\s+\\{[^}]*\\b${ep}\\b|\\{[^}]*\\b${ep}\\b[^}]*\\}\\s*=\\s*await\\s+import`);
                        const callLines = consumerContent.split("\n").filter(l => !importLinePattern.test(l) && l.includes(ep));
                        if (callLines.length > 0)
                            anyConsumerHasCall = true;
                        const hasModImport = entry.owner_files.some((ownerFile) => {
                            const ownerRelFromEngine = ownerFile.replace(/^src\/engine\//, "").replace(/\.ts$/, ".js");
                            return sourceImportsModule(consumerContent, `../../engine/${ownerRelFromEngine}`)
                                || sourceImportsModule(consumerContent, `../engine/${ownerRelFromEngine}`)
                                || sourceImportsModule(consumerContent, `./engine/${ownerRelFromEngine}`);
                        });
                        if (hasModImport)
                            anyConsumerImportsModule = true;
                    }
                    if (anyConsumerHasCall && anyConsumerImportsModule) {
                        consumedByRealCode = true;
                    }
                }
                if (!consumedByRealCode) {
                    for (const ownerFile of entry.owner_files) {
                        const ownerContent = safeReadCached(path.join(rootDir, ownerFile), ctx.readCache);
                        if (!ownerContent)
                            continue;
                        // 检查 entrypoint 在 owner_file 内部被非 export 行调用
                        const ownerLines = ownerContent.split("\n");
                        const exportLinePattern = new RegExp(`export\\s+(async\\s+)?function\\s+${ep}\\b|export\\s+const\\s+${ep}\\b`);
                        const internalCalls = ownerLines.filter(l => !exportLinePattern.test(l) && l.includes(ep));
                        if (internalCalls.length === 0)
                            continue; // entrypoint 在 owner_file 内部未被调用
                        // entrypoint 在 owner_file 内部被调用 — 检查消费者是否 import 了 owner_file 的任何函数
                        for (const consumerFile of consumerFiles) {
                            const consumerContent = safeReadCached(path.join(rootDir, consumerFile), ctx.readCache);
                            if (!consumerContent)
                                continue;
                            // 检查消费者是否从 owner_file import 了任何东西
                            const ownerBasename = ownerFile.replace(/^src\/engine\//, "").replace(/\.ts$/, ".js");
                            const ownerImportPattern = new RegExp(`from\\s+["']\\./${ownerBasename.replace(".js", "")}\\.js["']|from\\s+["']\\.\\./engine/${ownerBasename.replace(".js", "")}\\.js["']`);
                            // 对于 CLI: from "../engine/xxx.js"
                            const cliImportPattern = new RegExp(`\\bimport\\s*\\([^)]*${ownerBasename.replace(/\.js$/, "")}`);
                            if (ownerImportPattern.test(consumerContent) || cliImportPattern.test(consumerContent)) {
                                consumedByRealCode = true;
                                break;
                            }
                        }
                        if (consumedByRealCode)
                            break;
                    }
                }
                if (!consumedByRealCode) {
                    hardFail("MAINLINE_ENTRYPOINT_NOT_CONSUMED", `${reg.label}: ${entry.issue_id} 的 required_entrypoint "${ep}" 无真实消费路径 (直接或传递)`, [reg.filePath, ...consumerFiles, ...entry.owner_files], entry.issue_id, "旧 gate 不校验消费者是否真实调用入口函数", "补充消费者源码调用或修正 required_entrypoints");
                }
            }
            // ── 检查 5: owner_files 源码中必须包含调用链提到的函数名 ──
            let funcInSource = false;
            for (const ownerFile of entry.owner_files) {
                const srcContent = safeReadCached(path.join(rootDir, ownerFile), ctx.readCache);
                if (!srcContent)
                    continue;
                for (const seg of chainSegments) {
                    const funcName = seg.match(/([a-z][a-zA-Z_]{4,})/)?.[1];
                    if (funcName && sourceContainsIdentifier(srcContent, funcName)) {
                        funcInSource = true;
                        break;
                    }
                }
                if (funcInSource)
                    break;
            }
            if (!funcInSource) {
                hardFail("MAINLINE_CHAIN_FUNC_NOT_IN_OWNER", `${reg.label}: ${entry.issue_id} 的调用链函数名未在 owner_files 源码中找到`, [reg.filePath, ...entry.owner_files], entry.issue_id, "旧 gate 对调用链与 owner_files 交叉引用失败时仅发 _info", "修正调用链或 owner_files");
            }
        }
    }
}
//# sourceMappingURL=checkMainlineConsumption.js.map