import { createHash } from "node:crypto";
import { debug } from "../core/logger.js";
// 敏感内容模式 — 与 failure_report.ts 保持一致
const SENSITIVE_PATTERNS = [
    /sk-[a-zA-Z0-9]{20,}/g,
    /\b\d{11}\b/g,
    /password\s*[:=]\s*\S+/gi,
    /secret\s*[:=]\s*\S+/gi,
    /api_key\s*[:=]\s*\S+/gi,
    /token\s*[:=]\s*\S+/gi,
    /raw_stdout/gi,
    /raw_stderr/gi,
];
function redactErrorOutputForDebug(raw) {
    let result = raw;
    for (const pattern of SENSITIVE_PATTERNS) {
        result = result.replace(pattern, "[REDACTED]");
    }
    if (result.length > 500) {
        result = result.substring(0, 500) + "...[truncated]";
    }
    return result;
}
function stableHashForDebug(content) {
    return createHash("sha256").update(content).digest("hex").substring(0, 16);
}
/**
 * 调试器 — 对错误输出执行六步调试流水线分析。
 *
 * 流水线步骤：
 * 1. 错误解析（parseError）：将原始错误输出分类为编译错误、测试失败、运行时异常或未知类型
 * 2. 调用链提取（extractCallChain）：从堆栈跟踪中提取项目范围内的调用链
 * 3. 根因分析（analyzeRootCause）：基于规则引擎判定错误类型和来源阶段
 * 4. 修复建议（proposeFix）：根据错误类型提供定向修复策略
 * 5. 测试补充建议（suggestTests）：推荐与错误类型匹配的测试场景
 * 6. 结果汇总（debugError）：将以上步骤的结果组装为完整的调试会话
 */
/**
 * 上游阶段检测模式。
 * 用于判断错误是否源自需求、设计、权限、DDL 或 API 契约阶段，
 * 这类错误通常禁止自动修复，需人工介入。
 */
const PHASE_ORIGIN_PATTERNS = [
    { pattern: /requirement|需求|spec/i, phase: "requirement" },
    { pattern: /design|架构|设计|DDL|表结构|接口定义/i, phase: "design" },
    { pattern: /permission|权限|角色|授权/i, phase: "permission" },
    { pattern: /migration|数据库变更|schema/i, phase: "ddl" },
    { pattern: /api.*contract|接口契约|swagger/i, phase: "api_contract" },
];
// ── 第一步：错误解析（分类阶段） ──
/** 编译错误匹配模式 — 匹配 TypeScript 编译错误、类型不匹配、模块找不到等 */
const COMPILATION_PATTERNS = [
    /error TS\d+/,
    /error:/,
    /Cannot find/,
    /Type '.*' is not assignable/,
];
/** 测试失败匹配模式 — 匹配测试框架输出的失败标记和断言错误 */
const TEST_FAILURE_PATTERNS = [
    /FAIL|✕|×|AssertionError|expect\(/,
    /Test suite failed/,
];
/** 运行时异常匹配模式 — 匹配 JavaScript/TypeScript 常见的运行时错误类型 */
const RUNTIME_PATTERNS = [
    /Error:/,
    /Exception:/,
    /TypeError:/,
    /ReferenceError:/,
    /throw new/,
];
/** 源文件行号提取正则 — 从错误输出中提取 src/ 或 ./ 开头的源文件路径和行号 */
const FILE_LINE_PATTERN = /(?:src\/[^\s:(]+|\.\/[^\s:(]+)\.(?:ts|tsx|js|jsx)[\s(]*(\d+)/;
/**
 * 解析错误输出，将其分类为编译错误、测试失败、运行时异常或未知类型。
 * 同时提取文件路径、行号、错误消息和堆栈帧信息。
 * @param errorOutput - 原始错误输出文本
 * @returns 解析后的错误信息
 */
function parseError(errorOutput) {
    const lines = errorOutput.split("\n");
    const stack_frames = [];
    // 提取堆栈帧（格式为 "at functionName (file:line:column)"）
    for (const line of lines) {
        if (/^\s*at\s+/.test(line)) {
            stack_frames.push(line.trim());
        }
    }
    // 优先级 1: 编译错误（类型定义、导入路径问题等）
    for (const pattern of COMPILATION_PATTERNS) {
        if (pattern.test(errorOutput)) {
            const fileLineMatch = FILE_LINE_PATTERN.exec(errorOutput);
            const filePathMatch = /(?:src\/[^\s:(]+|\.\/[^\s:(]+)\.(?:ts|tsx|js|jsx)/.exec(errorOutput);
            return {
                error_type: "compilation",
                file: filePathMatch ? filePathMatch[0] : undefined,
                line: fileLineMatch ? parseInt(fileLineMatch[1], 10) : undefined,
                message: extractErrorMessage(errorOutput),
                stack_frames,
            };
        }
    }
    // 优先级 2: 测试失败（断言不通过、测试套件失败等）
    for (const pattern of TEST_FAILURE_PATTERNS) {
        if (pattern.test(errorOutput)) {
            const testNameMatch = /✕\s+(.+)/.exec(errorOutput) || /FAIL\s+(.+)/.exec(errorOutput);
            const assertionMatch = /AssertionError:\s*(.+)/.exec(errorOutput);
            return {
                error_type: "test_failure",
                message: assertionMatch
                    ? assertionMatch[1].trim()
                    : testNameMatch
                        ? testNameMatch[1].trim()
                        : extractErrorMessage(errorOutput),
                stack_frames,
            };
        }
    }
    // 优先级 3: 运行时异常（TypeError、ReferenceError 等）
    for (const pattern of RUNTIME_PATTERNS) {
        if (pattern.test(errorOutput)) {
            const exceptionMatch = /(TypeError|ReferenceError|Error|Exception|RangeError|SyntaxError):\s*(.+)/.exec(errorOutput);
            return {
                error_type: "runtime",
                message: exceptionMatch
                    ? `${exceptionMatch[1]}: ${exceptionMatch[2].trim()}`
                    : extractErrorMessage(errorOutput),
                stack_frames,
            };
        }
    }
    // 兜底: 无法归类的未知错误
    return {
        error_type: "unknown",
        message: extractErrorMessage(errorOutput),
        stack_frames,
    };
}
/**
 * 从错误输出中提取有意义的错误消息。
 * 优先提取包含 error/Error/FAIL/throw 等关键词的行，回退到第一行非空内容。
 * 截取最大 300 字符，避免过长消息。
 * @param errorOutput - 原始错误输出
 * @returns 提取到的错误消息文本
 */
function extractErrorMessage(errorOutput) {
    // 尝试提取包含错误关键词的行
    const lines = errorOutput.split("\n").filter((l) => l.trim().length > 0);
    for (const line of lines) {
        const trimmed = line.trim();
        if (/error|Error|FAIL|fail|throw|panic/i.test(trimmed)) {
            // 截取合理长度，防止消息过长
            return trimmed.length > 300 ? trimmed.substring(0, 300) + "..." : trimmed;
        }
    }
    // 回退：无关键词命中时，取第一行非空内容
    const first = lines[0]?.trim() ?? "";
    return first.length > 300 ? first.substring(0, 300) + "..." : first;
}
// ── 第二步：调用链提取 ──
/** 堆栈帧正则 — 匹配格式 "at functionName (filePath:line:column)" */
const STACK_FRAME_PATTERN = /at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/;
/**
 * 从错误输出中提取调用链。
 * 解析标准格式的堆栈帧，可选地过滤到项目范围内的帧。
 * @param errorOutput - 原始错误输出
 * @param projectScope - 可选的项目路径范围，仅保留路径包含这些前缀的帧
 * @returns 调用链项列表（按调用顺序排列）
 */
function extractCallChain(errorOutput, projectScope) {
    const chain = [];
    const scope = projectScope ?? [];
    const lines = errorOutput.split("\n");
    for (const line of lines) {
        const match = STACK_FRAME_PATTERN.exec(line.trim());
        if (!match)
            continue;
        const [, funcName, filePath, lineNum] = match;
        const lineNumber = parseInt(lineNum, 10);
        // 如果指定了项目范围，只保留范围内的帧
        if (scope.length > 0) {
            const inScope = scope.some((scopePath) => filePath.includes(scopePath));
            if (!inScope)
                continue;
        }
        chain.push({
            file: filePath,
            function: funcName,
            line: lineNumber,
        });
    }
    return chain;
}
// ── 第四步：根因分析 ──
/**
 * 基于规则引擎分析错误的根因。
 *
 * 判定规则（按优先级）：
 * 1. 上游阶段关键词匹配 → 确定性缺陷，禁止自动修复
 * 2. 编译错误 → 可修复（类型/导入问题）
 * 3. 测试失败 → 可修复（断言/数据问题）
 * 4. 同一错误重复 3 次以上 → 确定性缺陷
 * 5. 默认 → 可修复（通用错误）
 *
 * @param errorOutput - 原始错误输出
 * @param parsedError - 已解析的错误信息
 * @returns 根因分析结果（含失败类型、置信度和摘要）
 */
function analyzeRootCause(errorOutput, parsedError) {
    // 规则 1: 检测上游阶段关键词（需求、设计、权限、DDL、接口契约）
    for (const { pattern, phase } of PHASE_ORIGIN_PATTERNS) {
        if (pattern.test(errorOutput)) {
            return {
                failure_type: "deterministic",
                phase_origin: phase,
                summary: `根因追溯至 ${phase} 阶段，禁止自动修复`,
                confidence: 0.85,
            };
        }
    }
    // 规则 2: 编译错误 → 通常可修复（类型定义或导入路径问题）
    if (parsedError.error_type === "compilation") {
        return {
            failure_type: "fixable",
            summary: "编译错误，类型定义或导入路径问题",
            confidence: 0.7,
        };
    }
    // 规则 3: 测试失败 → 通常可修复（断言条件或测试数据问题）
    if (parsedError.error_type === "test_failure") {
        return {
            failure_type: "fixable",
            summary: "测试失败，需检查断言条件或测试数据",
            confidence: 0.6,
        };
    }
    // 规则 4: 同一错误重复出现 3 次及以上 → 确定性缺陷（可能是逻辑死循环或配置错误）
    const errorLines = errorOutput.split("\n").filter((l) => l.trim().length > 0);
    const firstErrorLine = errorLines[0]?.trim() ?? "";
    const repeatCount = errorLines.filter((l) => l.trim() === firstErrorLine).length;
    if (repeatCount >= 3) {
        return {
            failure_type: "deterministic",
            summary: `同一错误重复出现 ${repeatCount} 次，判定为确定性缺陷`,
            confidence: 0.9,
        };
    }
    // 规则 5: 默认兜底 — 通用可修复错误
    return {
        failure_type: "fixable",
        summary: "通用可修复错误，需要进一步上下文分析",
        confidence: 0.5,
    };
}
// ── 第五步：修复建议 ──
/**
 * 根据错误类型生成定向修复建议。
 *
 * 策略映射：
 * - compilation → 检查类型定义和导入路径（低风险）
 * - test_failure → 对比预期与实际输出（中风险）
 * - runtime → 添加空值检查和异常处理（中风险）
 * - unknown → 增加日志收集更多信息（高风险）
 *
 * @param parsedError - 已解析的错误信息
 * @param callChain - 调用链（用于定位相关文件）
 * @param _rootCause - 根因分析结果（当前版本未直接使用）
 * @returns 修复建议（包含描述、待检查文件、方法和风险等级）
 */
function proposeFix(parsedError, callChain, _rootCause) {
    switch (parsedError.error_type) {
        case "compilation": {
            // 编译错误：定位到出错文件，从顶层依赖逐步修复
            const filesToCheck = [];
            if (parsedError.file) {
                filesToCheck.push(parsedError.file);
            }
            return {
                description: "检查类型定义和导入路径",
                files_to_check: filesToCheck,
                approach: "逐步修复类型错误，从最上层的依赖开始",
                risk: "low",
            };
        }
        case "test_failure": {
            // 测试失败：从调用链中提取涉及的文件，对比预期和实际输出
            const filesToCheck = callChain
                .map((item) => item.file)
                .filter((f, i, arr) => arr.indexOf(f) === i); // 去重
            return {
                description: "检查断言条件和测试数据",
                files_to_check: filesToCheck,
                approach: "对比预期与实际输出，定位差异根因",
                risk: "medium",
            };
        }
        case "runtime": {
            // 运行时异常：从调用链定位异常位置，添加防御性代码
            const filesToCheck = callChain
                .map((item) => item.file)
                .filter((f, i, arr) => arr.indexOf(f) === i); // 去重
            return {
                description: "定位异常抛出位置，检查边界条件",
                files_to_check: filesToCheck,
                approach: "添加空值检查和异常处理",
                risk: "medium",
            };
        }
        case "unknown":
        default: {
            // 未知错误：建议先收集更多上下文信息
            return {
                description: "收集更多错误上下文信息",
                files_to_check: [],
                approach: "增加日志输出以获取更多诊断信息",
                risk: "high",
            };
        }
    }
}
// ── 第六步：测试补充建议 ──
/**
 * 根据错误类型推荐补充测试场景。
 * 每种错误类型对应不同的测试重点：
 * - compilation → 类型安全测试、编译时边界检查
 * - test_failure → 回归测试、等价类划分
 * - runtime → 空值/边界条件测试、异常处理路径
 * - unknown → 探索性测试
 * @param errorType - 已解析的错误类型
 * @returns 测试建议列表（含场景、覆盖范围和优先级）
 */
function suggestTests(errorType) {
    switch (errorType) {
        case "compilation":
            return [
                {
                    scenario: "类型安全测试",
                    covers: "确保类型定义与实际使用一致",
                    priority: "high",
                },
                {
                    scenario: "编译时边界检查",
                    covers: "验证极端类型场景和类型转换",
                    priority: "medium",
                },
            ];
        case "test_failure":
            return [
                {
                    scenario: "回归测试覆盖失败场景",
                    covers: "防止已修复问题再次出现",
                    priority: "high",
                },
                {
                    scenario: "等价类划分测试",
                    covers: "覆盖输入空间的典型和边界情况",
                    priority: "medium",
                },
            ];
        case "runtime":
            return [
                {
                    scenario: "空值/边界条件测试",
                    covers: "验证对 undefined、null、空数组等边界值的处理",
                    priority: "high",
                },
                {
                    scenario: "异常处理路径测试",
                    covers: "确保异常被正确捕获和恢复",
                    priority: "high",
                },
            ];
        case "unknown":
        default:
            return [
                {
                    scenario: "探索性测试用例",
                    covers: "通过手动和自动化手段探索潜在问题区域",
                    priority: "medium",
                },
            ];
    }
}
// ── 主入口：六步调试流水线 ──
/**
 * 执行完整的六步调试流水线。
 * 依次执行错误解析、调用链提取、根因分析、修复建议和测试补充，
 * 将结果组装为完整的调试会话对象。
 * @param errorOutput - 原始错误输出文本
 * @param taskId - 关联的任务 ID
 * @param projectScope - 可选的项目路径范围（用于过滤调用链帧）
 * @returns 完整的调试会话对象
 */
export function debugError(errorOutput, taskId, projectScope) {
    debug("调试器", `开始分析任务 ${taskId} 的错误`);
    const parsed_error = parseError(errorOutput);
    const call_chain = extractCallChain(errorOutput, projectScope);
    const root_cause = analyzeRootCause(errorOutput, parsed_error);
    const fix_proposal = proposeFix(parsed_error, call_chain, root_cause);
    const test_supplement = suggestTests(parsed_error.error_type);
    debug("调试器", `任务 ${taskId} 分析完成 — 错误类型: ${parsed_error.error_type}，根因: ${root_cause.failure_type}，置信度: ${root_cause.confidence}`);
    // 脱敏 — 不保留 raw error_output，只存脱敏摘要 + hash
    const redacted = redactErrorOutputForDebug(errorOutput);
    const hash = stableHashForDebug(errorOutput);
    return {
        task_id: taskId,
        error_output: redacted,
        error_output_hash: hash,
        parsed_error,
        call_chain,
        root_cause,
        fix_proposal,
        test_supplement,
    };
}
//# sourceMappingURL=debugger.js.map