import { debug } from "../core/logger.js";
// ── 内置规则 ──
const BUILTIN_RULES = [
    {
        id: "JAVA-Q001",
        severity: "hard_gate",
        description: "catch 块不能为空",
        pattern: null, // 特殊多行处理
        message: "空 catch 块会吞掉异常，导致调试困难",
    },
    {
        id: "JAVA-Q002",
        severity: "hard_gate",
        description: "不能使用 raw type",
        pattern: /^(?!.*import).*\b(ArrayList|HashMap|HashSet|LinkedList|LinkedHashMap|LinkedHashSet|TreeMap|TreeSet)\b[^<]/,
        message: "应使用泛型参数化类型，避免类型安全问题",
    },
    {
        id: "JAVA-Q003",
        severity: "hard_gate",
        description: "System.out.println 不应出现在生产代码",
        pattern: /System\.(out|err)\.(println|printf|print)\(/,
        message: "应使用日志框架而非 System.out/err",
    },
    {
        id: "JAVA-Q004",
        severity: "advisory",
        description: "方法过长（超过80行）",
        pattern: null, // 特殊处理
        message: "方法过长，建议拆分",
    },
    {
        id: "JAVA-Q005",
        severity: "hard_gate",
        description: "Thread.sleep 不应在生产代码中使用",
        pattern: /Thread\.sleep\s*\(/,
        message: "Thread.sleep 会阻塞线程，应使用异步等待机制",
    },
    {
        id: "JAVA-Q006",
        severity: "advisory",
        description: "检查是否缺少 @Override 注解",
        pattern: null, // 特殊处理
        message: "覆盖父类方法时应添加 @Override 注解",
    },
];
/**
 * 从项目约定文件加载自定义规则。
 * 项目约定优先于内置规则。
 */
export function loadProjectRules(conventionsContent) {
    debug("Java质量", "loadProjectRules() 开始执行");
    if (!conventionsContent)
        return [];
    const rules = [];
    const lines = conventionsContent.split("\n");
    for (const line of lines) {
        // 格式: JAVA-C### | hard_gate|advisory | description | pattern
        const match = line.match(/^(JAVA-[CQ]\d+)\s*\|\s*(hard_gate|advisory)\s*\|\s*(.+?)\s*\|\s*\/(.+)\/\s*$/);
        if (match) {
            rules.push({
                id: match[1],
                severity: match[2],
                description: match[3],
                pattern: new RegExp(match[4]),
                message: match[3],
            });
        }
    }
    return rules;
}
/**
 * 对 Java 源文件执行质量检查。
 * @param filePath - 文件路径
 * @param content - 文件内容
 * @param projectRules - 项目自定义规则（优先于内置规则）
 * @returns 质量检查报告
 */
export function checkJavaQuality(filePath, content, projectRules = []) {
    debug("Java质量", "checkJavaQuality() 开始执行，文件:", filePath);
    const results = [];
    const lines = content.split("\n");
    // 合并rules: project rules first, then built-in (project takes precedence by ID)
    const projectIds = new Set(projectRules.map((r) => r.id));
    const allRules = [...projectRules, ...BUILTIN_RULES.filter((r) => !projectIds.has(r.id))];
    debug("Java质量", "合并规则", allRules.length, "条（内置", BUILTIN_RULES.length, "条，自定义", projectRules.length, "条）");
    for (const rule of allRules) {
        if (rule.id === "JAVA-Q001") {
            // 空 catch 块（多行处理）
            checkEmptyCatch(filePath, lines, rule, results);
            continue;
        }
        if (rule.id === "JAVA-Q004") {
            // 方法长度检查（特殊处理）
            checkMethodLength(filePath, lines, rule, results);
            continue;
        }
        if (rule.id === "JAVA-Q006") {
            // @Override 检查（特殊处理）
            checkOverrideAnnotation(filePath, lines, rule, results);
            continue;
        }
        if (!rule.pattern)
            continue;
        for (let i = 0; i < lines.length; i++) {
            if (rule.pattern.test(lines[i])) {
                results.push({
                    rule_id: rule.id,
                    severity: rule.severity,
                    file_path: filePath,
                    line_number: i + 1,
                    message: rule.message,
                    detail: lines[i].trim(),
                });
            }
        }
    }
    const hardGateFailures = results.filter((r) => r.severity === "hard_gate").length;
    const advisoryWarnings = results.filter((r) => r.severity === "advisory").length;
    debug("Java质量", "检查完成 — hard_gate:", hardGateFailures, "失败，advisory:", advisoryWarnings, "警告，can_proceed:", hardGateFailures === 0);
    return {
        file_path: filePath,
        total_checks: allRules.length,
        hard_gate_failures: hardGateFailures,
        advisory_warnings: advisoryWarnings,
        results,
        can_proceed: hardGateFailures === 0,
        summary: hardGateFailures > 0
            ? `hard gate: ${hardGateFailures} failure(s), ${advisoryWarnings} advisory warning(s) — must fix before proceeding`
            : advisoryWarnings > 0
                ? `advisory: ${advisoryWarnings} warning(s) — review recommended but not required`
                : "all checks passed",
    };
}
function checkEmptyCatch(filePath, lines, rule, results) {
    const fullContent = lines.join("\n");
    const emptyCatchPat = /catch\s*\([^)]*\)\s*\{\s*\}/g;
    let match;
    while ((match = emptyCatchPat.exec(fullContent)) !== null) {
        // 查找line number from offset
        const offset = match.index;
        let lineNum = 1;
        for (let i = 0; i < offset; i++) {
            if (fullContent[i] === "\n")
                lineNum++;
        }
        results.push({
            rule_id: rule.id,
            severity: rule.severity,
            file_path: filePath,
            line_number: lineNum,
            message: rule.message,
            detail: match[0].trim(),
        });
    }
}
function checkMethodLength(filePath, lines, rule, results) {
    const MAX_METHOD_LINES = 80;
    let methodStart = -1;
    let braceDepth = 0;
    let methodName = "";
    for (let i = 0; i < lines.length; i++) {
        const line = lines[i].trim();
        // 检测method start
        if (methodStart === -1) {
            const methodMatch = line.match(/\b(public|private|protected|static|\s)+\s+\w+\s+\w+\s*\([^)]*\)\s*\{/);
            if (methodMatch) {
                methodStart = i;
                braceDepth = 1;
                const nameMatch = line.match(/(\w+)\s*\(/);
                methodName = nameMatch ? nameMatch[1] : "unknown";
                continue;
            }
        }
        if (methodStart >= 0) {
            for (const ch of line) {
                if (ch === "{")
                    braceDepth++;
                if (ch === "}")
                    braceDepth--;
            }
            if (braceDepth <= 0) {
                const methodLength = i - methodStart + 1;
                if (methodLength > MAX_METHOD_LINES) {
                    results.push({
                        rule_id: rule.id,
                        severity: rule.severity,
                        file_path: filePath,
                        line_number: methodStart + 1,
                        message: `${rule.message} (${methodName}: ${methodLength} lines)`,
                        detail: `方法 '${methodName}' 跨 ${methodLength} 行 (上限: ${MAX_METHOD_LINES})`,
                    });
                }
                methodStart = -1;
                braceDepth = 0;
            }
        }
    }
}
function checkOverrideAnnotation(filePath, lines, rule, results) {
    for (let i = 0; i < lines.length; i++) {
        const line = lines[i].trim();
        // 检查method that looks like an override (public/protected, has super-type signature)
        if (/\b(public|protected)\s+\w+\s+\w+\s*\([^)]*\)\s*\{/.test(line) &&
            !lines[Math.max(0, i - 1)].trim().startsWith("@Override") &&
            !lines[Math.max(0, i - 1)].trim().startsWith("@")) {
            // 启发式: 如果方法名包含常见的 override 模式
            const nameMatch = line.match(/(\w+)\s*\(/);
            const methodName = nameMatch ? nameMatch[1] : "";
            const commonOverrides = [
                "toString", "equals", "hashCode", "compareTo",
                "run", "call", "execute",
                "setUp", "tearDown", "beforeEach", "afterEach",
            ];
            if (commonOverrides.includes(methodName)) {
                results.push({
                    rule_id: rule.id,
                    severity: rule.severity,
                    file_path: filePath,
                    line_number: i + 1,
                    message: `${rule.message} (${methodName})`,
                    detail: line,
                });
            }
        }
    }
}
//# sourceMappingURL=java_quality_guard.js.map