/**
 * intent_expander — knowledge querying and loading helpers.
 *
 * Functions for querying the knowledge index, loading builtin templates,
 * converting project knowledge assets, and matching templates by name.
 */
import path from "node:path";
import { fileURLToPath } from "node:url";
import fss from "node:fs";
import matter from "gray-matter";
import { getContractDecision } from "../../templates/template_asset_contract_registry.js";
import { parseFrontmatterVisibility } from "../../templates/template_asset_visibility.js";
import { debugLog } from "../../core/logger.js";
import { extractKeywords, matchesTemplateByName } from "./helpers.js";
/** 阶段 → 推荐查询类型的映射 */
const STAGE_TYPE_MAP = {
    "需求分析": ["domain", "procedure", "artifact_template"],
    "现有系统分析": ["domain", "pattern", "procedure", "artifact_template"],
    "架构设计": ["pattern", "domain", "procedure", "artifact_template"],
    "详细设计": ["pattern", "domain", "procedure", "artifact_template"],
    "任务规划": ["pipeline_procedure", "procedure", "artifact_template"],
    "编码与单元测试": ["pattern", "procedure", "review_rule", "artifact_template"],
    "代码审查": ["review_rule", "pattern", "checklist", "artifact_template"],
    "联调验证": ["review_rule", "procedure", "domain", "checklist", "artifact_template"],
};
export function knowledgeTypeForProjectAsset(asset) {
    if (asset.consumption === "acceptance_template")
        return "acceptance_template";
    if (asset.consumption === "review_rule")
        return "review_rule";
    if (asset.consumption === "hard_rule")
        return "governance_rule";
    if (asset.rel_path.includes("procedures/"))
        return "procedure";
    if (asset.rel_path.includes("domain/"))
        return "domain";
    return "governance_rule";
}
export function readProjectKnowledgeBody(asset) {
    try {
        const raw = fss.readFileSync(asset.abs_path, "utf-8");
        if (/\.md$/i.test(asset.abs_path))
            return matter(raw).content.trim();
        return raw.trim();
    }
    catch {
        return "";
    }
}
export function projectKnowledgeAssetToEntry(asset) {
    const body = readProjectKnowledgeBody(asset);
    if (!body)
        return null;
    const now = new Date().toISOString();
    return {
        id: `project:${asset.id}`,
        file_path: asset.abs_path,
        name: asset.name,
        type: knowledgeTypeForProjectAsset(asset),
        when: [...asset.routes, ...asset.primary_triggers, ...asset.domains].join(", "),
        body,
        scope: ["shared"],
        products: ["*"],
        tech_stack: asset.tech_stack.join(","),
        created_at: now,
        updated_at: now,
        usage_count: 0,
        confidence: asset.hard_rule ? 1 : 0.85,
        status: "active",
    };
}
/**
 * 根据 pipeline_hint 名称加载内置流程模板。
 */
export function loadBuiltinByPipeline(pipelineName) {
    const entries = [];
    // pipeline_hint 格式: source-prototype-to-delivery:step-1 → 找源码原型交付流程.md
    const nameToTemplate = {
        "source-prototype-to-delivery": "源码原型交付流程.md",
    };
    const templateFile = nameToTemplate[pipelineName];
    if (templateFile) {
        const entry = loadBuiltinTemplate(templateFile, "procedures");
        if (entry)
            entries.push(entry);
    }
    return entries;
}
/** 包内模板知识库根目录 */
function getTemplatesRoot() {
    const thisDir = path.dirname(fileURLToPath(import.meta.url));
    // src/engine/pipeline/intent_expander/ → ../../../.. → 项目根 → templates
    return path.resolve(thisDir, "..", "..", "..", "..", "templates");
}
/**
 * 当知识索引中没有找到内置模板时，从 templates/ 加载为 KnowledgeEntry。
 * 只加载指定名称的文件。
 */
function loadBuiltinTemplate(fileName, subDir) {
    const templatesRoot = getTemplatesRoot();
    const safeName = path.basename(fileName); // basename 防止路径穿越
    const filePath = path.join(templatesRoot, subDir, safeName);
    try {
        if (!fss.existsSync(filePath))
            return null;
        // 合同门禁: getContractDecision 统一裁决
        const relPath = `templates/${subDir}/${safeName}`;
        const decision = getContractDecision(relPath);
        if (decision.decision !== "allowed") {
            debugLog("意图扩展: 内置模板被合同门禁阻断 —", relPath, decision.decision);
            return null;
        }
        const raw = fss.readFileSync(filePath, "utf-8");
        const fmVis = parseFrontmatterVisibility(raw);
        if (fmVis === "soloforge_internal" || fmVis === "adapter_runtime_only" || fmVis === "scaffold_only") {
            debugLog("意图扩展: 内置模板 frontmatter 可见性阻断 —", relPath, fmVis);
            return null;
        }
        const { data, content: body } = matter(raw);
        const name = data.name || path.basename(fileName, ".md");
        const type = data.type || inferTypeFromSubDir(subDir);
        return {
            id: `builtin-${name}`,
            file_path: filePath,
            name,
            type,
            when: data.when || "",
            body,
            scope: data.scope || ["shared"],
            products: data.products || ["*"],
            tech_stack: data.tech_stack,
            created_at: data.created_at || new Date().toISOString().split("T")[0],
            updated_at: data.updated_at || new Date().toISOString().split("T")[0],
            usage_count: 0,
            confidence: data.confidence ?? 1.0,
            status: "active",
        };
    }
    catch (e) {
        debugLog("意图扩展: 内置模板加载失败 —", e);
        return null;
    }
}
function inferTypeFromSubDir(subDir) {
    if (subDir.includes("procedures"))
        return "pipeline_procedure";
    if (subDir.includes("acceptance_templates"))
        return "acceptance_template";
    if (subDir.includes("review_rules"))
        return "review_rule";
    if (subDir.includes("domain"))
        return "domain";
    return "pattern";
}
/**
 * 路由驱动的知识匹配。
 * 优先使用 pipeline_hint、output_artifact.kind、route + execution_shape，
 * 降级为同类型通用产物 prompt，不退化成编码 prompt。
 */
export function queryKnowledgeForRoute(knowledgeIndex, intent, scopeFilters, config, routeDecision, limit, taskStage) {
    if (!routeDecision) {
        // 无 route_decision 时回退到旧逻辑（不传 route，不强制路由匹配）
        return knowledgeIndex.query({
            scope: scopeFilters,
            products: [config.product_profile],
            keywords: extractKeywords(intent),
            limit,
        });
    }
    const currentRoute = routeDecision.route;
    const seen = new Set();
    const results = [];
    function addEntries(entries) {
        for (const e of entries) {
            if (!seen.has(e.id)) {
                seen.add(e.id);
                results.push(e);
            }
        }
    }
    // 优先级 1: pipeline_hint 精确匹配（不提前 return）
    if (routeDecision.pipeline_hint) {
        const pipelineName = routeDecision.pipeline_hint.split(":")[0];
        const pipelineResults = knowledgeIndex.query({
            scope: scopeFilters,
            products: [config.product_profile],
            type: "pipeline_procedure",
            route: currentRoute,
            keywords: extractKeywords(pipelineName),
            limit: 3,
        });
        addEntries(pipelineResults);
        // 内置模板回退: pipeline_hint 名称未命中时从 templates/ 加载
        if (pipelineResults.length === 0) {
            const builtin = loadBuiltinByPipeline(pipelineName);
            if (builtin)
                addEntries(builtin);
        }
    }
    // 优先级 2: output_artifact.kind 映射 acceptance_template（不提前 return）
    if (routeDecision.output_artifact?.kind) {
        // 先按 template 文件名精确匹配
        const templateName = routeDecision.output_artifact.template;
        if (templateName) {
            const allTemplates = knowledgeIndex.query({
                scope: scopeFilters,
                products: [config.product_profile],
                type: "acceptance_template",
                route: currentRoute,
                keywords: [],
                limit: 100,
            });
            const exactMatch = allTemplates.find((e) => matchesTemplateByName(e, templateName));
            if (exactMatch)
                addEntries([exactMatch]);
            // 内置模板回退: template 名称未命中时从 templates/artifacts/shared/ 加载
            if (!exactMatch) {
                const builtinTemplate = loadBuiltinTemplate(templateName, "artifacts/shared");
                if (builtinTemplate)
                    addEntries([builtinTemplate]);
            }
        }
        // 再按 artifact kind 关键词匹配
        const artifactKeywords = {
            prototype_spec: ["原型", "prototype", "原型说明"],
            api_spec: ["接口", "API", "接口设计"],
            design_doc: ["设计", "架构", "详细设计"],
            test_plan: ["测试", "测试计划"],
            migration_plan: ["迁移", "迁移方案"],
            review_report: ["审查", "review"],
            task_breakdown: ["任务", "拆解"],
            root_cause: ["根因", "分析"],
            incident_review: ["故障", "复盘"],
        };
        const artifactKws = artifactKeywords[routeDecision.output_artifact.kind] ?? [];
        if (artifactKws.length > 0) {
            const templateResults = knowledgeIndex.query({
                scope: scopeFilters,
                products: [config.product_profile],
                type: "acceptance_template",
                keywords: artifactKws,
                limit: 2,
            });
            addEntries(templateResults);
        }
    }
    // 优先级 2.5: 阶段匹配的多类型知识查询
    const relevantTypes = taskStage
        ? (STAGE_TYPE_MAP[taskStage] ?? ["pattern"])
        : ["pattern", "procedure", "domain", "review_rule", "artifact_template"];
    const TYPE_BUDGET = 2;
    const seenTypes = new Set();
    for (const type of relevantTypes) {
        if (seenTypes.has(type))
            continue;
        const typeResults = knowledgeIndex.query({
            scope: scopeFilters,
            products: [config.product_profile],
            type,
            route: currentRoute,
            stages: taskStage ? [taskStage] : undefined,
            limit: TYPE_BUDGET,
        });
        for (const entry of typeResults) {
            addEntries([entry]);
        }
        seenTypes.add(type);
    }
    // 优先级 3: intent keywords 补充（填满 limit）
    if (results.length < limit) {
        const keywordResults = knowledgeIndex.query({
            scope: scopeFilters,
            products: [config.product_profile],
            route: currentRoute,
            keywords: extractKeywords(intent),
            limit: limit,
        });
        addEntries(keywordResults);
    }
    // 合同门禁: 对 templates/ 相对路径统一裁决，过滤 denied 和 unregistered
    const filtered = results.filter((entry) => {
        if (!entry.file_path)
            return true;
        // 只对 templates/ 开头的相对路径执行合同裁决
        const normalized = entry.file_path.replace(/\\/g, "/");
        if (!normalized.startsWith("templates/"))
            return true;
        const decision = getContractDecision(normalized);
        if (decision.decision !== "allowed")
            return false;
        // 技术栈过滤: 合同声明了 applicable_tech_stack 时必须匹配当前项目技术栈
        if (decision.contract && decision.contract.applicable_tech_stack.length > 0) {
            const currentStack = [
                config.tech_stack?.backend?.framework,
                config.tech_stack?.frontend?.framework,
                config.tech_stack?.backend?.lang,
                config.tech_stack?.frontend?.lang,
            ].filter(Boolean);
            const hasMatch = decision.contract.applicable_tech_stack.some((t) => currentStack.some((s) => s.toLowerCase().includes(t.toLowerCase()) || t.toLowerCase().includes(s.toLowerCase())));
            if (!hasMatch)
                return false;
        }
        return true;
    });
    return filtered.slice(0, limit);
}
//# sourceMappingURL=knowledge.js.map