/**
 * 意图路由评分器 — 根据结构化信号和材料打分，确定路由。
 *
 * 不再依赖单条整句正则，而是通过信号提取 → 归一化 → 打分 → 冲突仲裁。
 * 支持乱序表达、路径不在句首、中文标点、换行、多空格。
 */
import { findArtifactAlias, getArtifactAliases } from "./intent_signal_extractor.js";
// ── 路由 → 分数映射 ──
function hasAction(signals, cat) {
    return signals.actions.some((a) => a.category === cat);
}
function hasArtifactKind(signals) {
    return signals.artifacts.length > 0;
}
function hasNegation(signals, target) {
    return signals.negations.some((n) => n.negates === target);
}
function hasConstraint(signals, type) {
    return signals.constraints.some((c) => c.type === type);
}
function detectArtifactFromSignals(signals) {
    for (const sig of signals.artifacts) {
        const alias = findArtifactAlias(sig.kind);
        if (alias) {
            return { kind: alias.kind, defaultName: alias.defaultName, template: alias.template };
        }
    }
    return undefined;
}
function detectGenericArtifact(intent, _taskId) {
    for (const alias of getArtifactAliases()) {
        if (alias.patterns.some((p) => p.test(intent))) {
            return { kind: alias.kind, defaultName: alias.defaultName, template: alias.template };
        }
    }
    if (/(?:文档|方案|规约|计划|清单|报告|说明文档)$/.test(intent)) {
        const match = intent.match(/([一-龥]+(?:文档|方案|规约|计划|清单|报告|说明文档))$/);
        const name = match ? match[1] : "产物";
        return { kind: "unknown", defaultName: name };
    }
    return undefined;
}
function inferPipelineHint(intent, artifactKind) {
    if (/源码.*原型|原型.*源码|源码包.*原型|prototype/i.test(intent)) {
        return "source-prototype-to-delivery:step-1";
    }
    if (/从.*(?:设计|需求|原型).*到.*(?:交付|完成)/.test(intent)) {
        return "source-prototype-to-delivery";
    }
    switch (artifactKind) {
        case "prototype_spec": return "source-prototype-to-delivery:step-1";
        case "api_spec": return "source-prototype-to-delivery:step-4";
        case "design_doc": return "source-prototype-to-delivery:step-3";
        case "test_plan": return "source-prototype-to-delivery:step-5";
        default: return undefined;
    }
}
// ── 主评分函数 ──
export function scoreRoute(intent, signals, materials, taskId) {
    const scores = [];
    const evidence = [];
    const hasPaths = materials.materials.length > 0;
    // ── 1. 跳过评分 ──
    if (signals.is_skip) {
        scores.push({ route: "skip_chat", score: 100, reasons: [`skip_detected:${signals.skip_reason}`] });
        evidence.push(`skip:${signals.skip_reason}`);
    }
    // ── 2. 通用问答 ──
    if (signals.is_general_qa) {
        scores.push({ route: "direct_answer", score: 90, reasons: ["general_qa_pattern"] });
        evidence.push("general_qa");
    }
    // ── 3. 源码提取评分 ──
    const hasSourceMaterial = signals.source_material_kinds.length > 0;
    const hasExtractAction = hasAction(signals, "extract");
    const hasExtractionVerb = signals.has_extraction_structure;
    const hasSourceSignal = hasSourceMaterial || (hasExtractionVerb && (hasPaths || /源码/.test(intent)));
    const hasArtifactVerb = hasAction(signals, "generate") || hasExtractAction;
    const artifactFromSignals = detectArtifactFromSignals(signals);
    const artifactGeneric = detectGenericArtifact(intent, taskId);
    const artifact = artifactFromSignals ?? artifactGeneric;
    const hasArtifactNoun = hasArtifactKind(signals) || !!artifactGeneric;
    const hasArtifactVerbAndNoun = hasArtifactVerb && hasArtifactNoun;
    if (hasSourceSignal && (hasArtifactVerbAndNoun || artifact)) {
        const mutationBlocked = hasNegation(signals, "mutation") || hasConstraint(signals, "no_mutation");
        const s = mutationBlocked ? 95 : 85;
        scores.push({
            route: "source_extraction",
            score: s,
            reasons: [
                hasSourceMaterial ? `source_material:${signals.source_material_kinds.join(",")}` : "extraction_structure",
                hasExtractAction ? "extract_action" : "extraction_verb",
                artifact ? `artifact:${artifact.kind}` : "no_artifact",
                mutationBlocked ? "mutation_blocked" : "",
            ].filter(Boolean),
        });
        evidence.push(`source_extraction:${hasSourceMaterial ? "material" : "structure"}`);
    }
    // ── 4. 规划评分 ──
    if (hasAction(signals, "plan")) {
        const pipelineBlocked = hasNegation(signals, "pipeline") || hasConstraint(signals, "no_pipeline");
        if (signals.has_full_pipeline && !pipelineBlocked) {
            scores.push({ route: "planning", score: 88, reasons: ["plan_action", "full_pipeline"] });
            evidence.push("planning:multi_stage");
        }
        else {
            scores.push({ route: "planning", score: 82, reasons: ["plan_action"] });
            evidence.push("planning:single");
        }
    }
    // ── 5. 操作评分 ──
    if (hasAction(signals, "operate")) {
        scores.push({ route: "operation", score: 82, reasons: ["operate_action"] });
        evidence.push("operation");
    }
    // ── 6. 分析评分 ──
    if (hasAction(signals, "analyze") && !hasArtifactVerb) {
        scores.push({ route: "analysis", score: 80, reasons: ["analyze_action", "no_artifact_verb"] });
        evidence.push("analysis");
    }
    // ── 7. 产物生成评分 ──
    if (hasArtifactVerbAndNoun || (hasArtifactVerb && artifact && !signals.is_pure_explain)) {
        if (!hasSourceSignal) {
            scores.push({
                route: "artifact_generation",
                score: 80,
                reasons: ["artifact_verb+noun", artifact ? `artifact:${artifact.kind}` : ""].filter(Boolean),
            });
            evidence.push("artifact_generation");
        }
    }
    // ── 8. 代码修改评分 ──
    if (hasAction(signals, "code_change")) {
        scores.push({ route: "code_change", score: 85, reasons: ["code_change_action"] });
        evidence.push("code_change");
    }
    // ── 9. 审查评分 ──
    if (hasAction(signals, "review")) {
        scores.push({ route: "review", score: 85, reasons: ["review_action"] });
        evidence.push("review");
    }
    // ── 10. 验收/就绪检查评分 ──
    if (hasAction(signals, "acceptance")) {
        const hasImplementationVerb = /修复|实现|开发|新增|添加|修改|变更|重构|删除|移除|替换|补(?:单元)?测试|写测试|编码/.test(intent);
        if (!hasImplementationVerb && !hasArtifactVerb) {
            scores.push({ route: "acceptance", score: 92, reasons: ["acceptance_action", "read_only_readiness"] });
            evidence.push("acceptance");
        }
        else {
            scores.push({ route: "acceptance", score: 65, reasons: ["acceptance_action", "implementation_or_artifact_present"] });
        }
    }
    // ── 11. 通用分析（低优先） ──
    if (hasAction(signals, "analyze")) {
        const alreadyScored = scores.some((s) => s.route === "analysis");
        if (!alreadyScored) {
            scores.push({ route: "analysis", score: 70, reasons: ["analyze_action_fallback"] });
            evidence.push("analysis:fallback");
        }
    }
    // ── 12. 灰区 ──
    if (signals.gray_zone === "organize" && !hasArtifactNoun) {
        scores.push({ route: "direct_answer", score: 60, reasons: ["gray_zone:organize_no_artifact"] });
        evidence.push("gray:organize");
    }
    if (signals.gray_zone === "look") {
        if (/风险|问题|有没有/.test(intent)) {
            scores.push({ route: "review", score: 70, reasons: ["gray_zone:look+risk"] });
            evidence.push("gray:review");
        }
        else {
            scores.push({ route: "direct_answer", score: 55, reasons: ["gray_zone:look"] });
            evidence.push("gray:look");
        }
    }
    // ── 13. 纯解释 ──
    if (signals.is_pure_explain) {
        if (/(?:这个|这|项目里|项目中的|当前|现有)/.test(intent)) {
            scores.push({ route: "analysis", score: 70, reasons: ["pure_explain+context"] });
            evidence.push("explain:analysis");
        }
        else {
            scores.push({ route: "direct_answer", score: 85, reasons: ["pure_explain"] });
            evidence.push("explain:direct");
        }
    }
    // ── 选择最高分路由 ──
    scores.sort((a, b) => b.score - a.score);
    const winner = scores[0];
    // ── 兜底 ──
    if (!winner) {
        return {
            route: "direct_answer",
            execution_shape: "none",
            mutation_allowed: false,
            confidence: 0.3,
            needs_clarification: false,
            route_reason: "no_matching_signal",
            signal_evidence: [],
            score_breakdown: [],
        };
    }
    // ── 确定执行形态 ──
    let executionShape;
    let mutationAllowed;
    let needsClarification = false;
    const routeReason = winner.reasons.join(", ");
    switch (winner.route) {
        case "skip_chat":
        case "direct_answer":
            executionShape = "none";
            mutationAllowed = false;
            break;
        case "source_extraction":
            executionShape = "single_artifact";
            mutationAllowed = false; // source_extraction 永远不允许 mutation
            break;
        case "artifact_generation":
            executionShape = "single_artifact";
            mutationAllowed = false;
            break;
        case "code_change":
            executionShape = "code_execution";
            mutationAllowed = hasNegation(signals, "mutation") ? false : true;
            break;
        case "analysis":
            executionShape = "read_only_analysis";
            mutationAllowed = false;
            break;
        case "review":
            executionShape = "read_only_analysis";
            mutationAllowed = false;
            break;
        case "acceptance":
            executionShape = "read_only_analysis";
            mutationAllowed = false;
            break;
        case "planning":
            executionShape = signals.has_full_pipeline && !hasNegation(signals, "pipeline") ? "multi_stage_plan" : "single_artifact";
            mutationAllowed = false;
            break;
        case "operation":
            executionShape = "verification_only";
            mutationAllowed = false;
            break;
        default:
            executionShape = "none";
            mutationAllowed = false;
    }
    // ── 低置信策略：有材料+动作但不 skip ──
    const lowConfidenceButHasMaterial = (hasPaths || materials.inferred.length > 0) && hasArtifactVerb;
    if (winner.route === "direct_answer" && lowConfidenceButHasMaterial && !signals.is_skip && !signals.is_pure_explain && !signals.is_general_qa) {
        // 升级到 source_extraction 或 artifact_generation 而非 skip
        if (hasPaths) {
            return {
                route: "source_extraction",
                execution_shape: "single_artifact",
                mutation_allowed: false,
                confidence: 0.6,
                needs_clarification: true,
                route_reason: "upgraded_from_low_confidence_with_material",
                signal_evidence: evidence,
                score_breakdown: scores,
                skip_reason: undefined,
                artifact: artifact ?? { kind: "custom", defaultName: "提取产物" },
                pipeline_hint: inferPipelineHint(intent, artifact?.kind),
            };
        }
    }
    // ── 缺路径 clarification ──
    if ((winner.route === "source_extraction" || winner.route === "artifact_generation") && !hasPaths) {
        needsClarification = true;
    }
    // ── 根据 PRD/需求 引用补充 missing ──
    if (winner.route === "artifact_generation" && !hasPaths) {
        if (/根据\s*(?:PRD|需求文档|原型|接口文档|设计文档|源码)/i.test(intent)) {
            needsClarification = true;
        }
    }
    // ── 冲突仲裁："从源码包提取原型说明，不要修改代码" ──
    // source_extraction + code_change 动作 → source_extraction, mutation=false
    if (hasSourceSignal && hasAction(signals, "code_change") && hasNegation(signals, "mutation")) {
        if (winner.route !== "source_extraction") {
            // 强制降级为 source_extraction
            const seScore = scores.find((s) => s.route === "source_extraction");
            if (seScore) {
                return {
                    route: "source_extraction",
                    execution_shape: "single_artifact",
                    mutation_allowed: false,
                    confidence: seScore.score / 100,
                    needs_clarification: needsClarification,
                    route_reason: "conflict_arbitration:source_extraction_over_code_change",
                    signal_evidence: evidence,
                    score_breakdown: scores,
                    skip_reason: undefined,
                    artifact,
                    pipeline_hint: inferPipelineHint(intent, artifact?.kind),
                };
            }
        }
    }
    // ── 冲突仲裁："从 UserService 提取公共方法" 无外部材料 → code_change ──
    if (hasExtractionVerb && !hasSourceSignal && !hasPaths && hasAction(signals, "code_change")) {
        if (winner.route === "source_extraction") {
            // 降级为 code_change
            const ccScore = scores.find((s) => s.route === "code_change");
            if (ccScore) {
                return {
                    route: "code_change",
                    execution_shape: "code_execution",
                    mutation_allowed: true,
                    confidence: ccScore.score / 100,
                    needs_clarification: false,
                    route_reason: "conflict_arbitration:code_change_over_extraction_no_material",
                    signal_evidence: evidence,
                    score_breakdown: scores,
                    skip_reason: undefined,
                    artifact: undefined,
                    pipeline_hint: undefined,
                };
            }
        }
    }
    return {
        route: winner.route,
        execution_shape: executionShape,
        mutation_allowed: mutationAllowed,
        confidence: winner.score / 100,
        needs_clarification: needsClarification,
        route_reason: routeReason,
        signal_evidence: evidence,
        score_breakdown: scores,
        skip_reason: winner.route === "skip_chat" ? signals.skip_reason : undefined,
        artifact,
        pipeline_hint: ["source_extraction", "artifact_generation", "planning"].includes(winner.route)
            ? inferPipelineHint(intent, artifact?.kind)
            : undefined,
    };
}
//# sourceMappingURL=intent_route_scorer.js.map