import { debug } from "./core/logger.js";
/**
 * 数据库迁移守卫 — 逐行分析 SQL 迁移脚本，检测高风险操作（DROP TABLE、DELETE 无 WHERE 等），
 * 并生成中文风险摘要和回滚建议。纯规则匹配，零 AI 依赖。
 */
/** 回滚建议模板 — 按 SQL 语句类型映射到对应的回滚操作建议 */
// ── 回滚建议模板（按语句类型索引） ──
const ROLLBACK_SUGGESTIONS = {
    DROP_TABLE: "恢复数据需要从备份还原，建议先创建备份",
    DROP_COLUMN: "此操作不可逆，建议先迁移数据到新列",
    DELETE_NO_WHERE: "建议添加 WHERE 条件或使用事务包装",
    ALTER_COLUMN: "修改列类型前建议备份数据，并验证兼容性",
    TRUNCATE: "清空操作不可逆，建议先创建数据备份",
    ADD_NOT_NULL: "建议添加 DEFAULT 值或分步执行（先加可为空列→回填→改非空）",
    RENAME: "重命名操作需确认无其他代码引用该名称",
    ADD_INDEX: "大表添加索引可能造成长时间锁表，建议在低峰期执行",
    ADD_FK: "添加外键前建议确认引用完整性，并在低峰期执行",
};
/**
 * 从 SQL 行中提取表名 — 支持 TABLE/FROM/INTO 三种常见语法位置。
 * @param line - 已转大写的 SQL 行
 * @returns 提取到的表名，未匹配时返回 undefined
 */
function extractTableFrom(line) {
    // TABLE <name>（覆盖 DROP TABLE、ALTER TABLE、CREATE TABLE、RENAME TABLE）
    const tableMatch = line.match(/TABLE\s+(\w+)/);
    if (tableMatch)
        return tableMatch[1];
    // FROM <name>（覆盖 DELETE FROM、INSERT INTO）
    const fromMatch = line.match(/FROM\s+(\w+)/);
    if (fromMatch)
        return fromMatch[1];
    // INTO <name>（覆盖 INSERT INTO）
    const intoMatch = line.match(/INTO\s+(\w+)/);
    if (intoMatch)
        return intoMatch[1];
    return undefined;
}
/** 高风险规则集 — 检测 DROP TABLE、DROP COLUMN、修改列类型、DELETE 无 WHERE、TRUNCATE 等危险操作 */
const CRITICAL_RULES = [
    {
        test: (upper) => /DROP\s+TABLE/.test(upper),
        type: "DROP_TABLE",
        risk: "critical",
        description: "删除表操作，数据不可恢复",
    },
    {
        test: (upper) => /DROP\s+COLUMN/.test(upper),
        type: "DROP_COLUMN",
        risk: "critical",
        description: "删除列操作，数据不可恢复",
    },
    {
        test: (upper, _raw) => {
            if (!/ALTER\s+COLUMN/.test(upper) && !/ALTER\s+TABLE\b/.test(upper))
                return false;
            // 检测列类型变更模式: TYPE、USING、SET DATA TYPE 关键字
            return /TYPE\s|SET\s+DATA\s+TYPE\s|USING\s/.test(upper);
        },
        type: "ALTER_COLUMN",
        risk: "critical",
        description: "修改列类型可能导致数据丢失",
    },
    {
        test: (upper) => /MODIFY\s+COLUMN/.test(upper),
        type: "ALTER_COLUMN",
        risk: "critical",
        description: "MySQL MODIFY COLUMN 修改列类型可能导致数据丢失",
    },
    {
        test: (upper) => /CHANGE\s+COLUMN/.test(upper),
        type: "ALTER_COLUMN",
        risk: "critical",
        description: "MySQL CHANGE COLUMN 修改列定义可能导致数据丢失",
    },
    {
        test: (upper, _raw, _lines, _lineIndex) => {
            if (!/DELETE\s+FROM/.test(upper))
                return false;
            // 当前行无 WHERE — 向后预查最多 10 行，寻找 WHERE 子句或语句结束符(;)
            if (/WHERE\b/.test(upper))
                return false;
            // 向后预查最多 10 行，若遇到分号则语句结束
            const lines = _lines;
            const startIdx = _lineIndex;
            const lookAheadLimit = Math.min(lines.length, startIdx + 10);
            for (let j = startIdx + 1; j < lookAheadLimit; j++) {
                const futureLine = lines[j].trim().toUpperCase();
                if (futureLine.startsWith("--"))
                    continue; // 跳过注释行
                if (/WHERE\b/.test(futureLine))
                    return false;
                if (/;\s*$/.test(futureLine) || futureLine.endsWith(";"))
                    break; // 语句结束
            }
            return true;
        },
        type: "DELETE_NO_WHERE",
        risk: "critical",
        description: "无条件删除，将清空表数据",
    },
    {
        test: (upper) => /TRUNCATE\s+TABLE/.test(upper) || /TRUNCATE\b/.test(upper),
        type: "TRUNCATE",
        risk: "critical",
        description: "清空表操作",
    },
];
/** 警告规则集 — 检测 ADD COLUMN 无 DEFAULT 的 NOT NULL、RENAME、添加索引、添加外键等需谨慎操作 */
const WARNING_RULES = [
    {
        test: (upper, _raw) => {
            if (!/ADD\s+COLUMN/.test(upper))
                return false;
            // 存在 NOT NULL 但无 DEFAULT
            return /NOT\s+NULL/.test(upper) && !/DEFAULT\s/.test(upper);
        },
        type: "ADD_NOT_NULL",
        risk: "warning",
        description: "添加非空列无默认值，需回填数据",
    },
    {
        test: (upper) => /RENAME\s+(TABLE|COLUMN)/.test(upper),
        type: "RENAME",
        risk: "warning",
        description: "重命名操作，需确认无其他引用",
    },
    {
        test: (upper) => /ADD\s+(UNIQUE\s+)?INDEX|CREATE\s+(UNIQUE\s+)?INDEX/.test(upper),
        type: "ADD_INDEX",
        risk: "warning",
        description: "添加索引可能导致锁表",
    },
    {
        test: (upper) => /ADD\s+CONSTRAINT\b/.test(upper) && /FOREIGN\s+KEY/.test(upper),
        type: "ADD_FK",
        risk: "warning",
        description: "添加外键约束，需确认引用完整性",
    },
];
/** 安全规则集 — 检测 CREATE TABLE、ADD COLUMN（可空/有默认值）、INSERT、COMMENT 等低风险操作 */
const SAFE_RULES = [
    {
        test: (upper) => /CREATE\s+TABLE/.test(upper),
        type: "CREATE_TABLE",
        risk: "safe",
        description: "创建表操作",
    },
    {
        test: (upper, _raw) => {
            if (!/ADD\s+COLUMN/.test(upper))
                return false;
            // 明确指定为可空，或有默认值
            const hasNull = /\bNULL\b/.test(upper) && !/NOT\s+NULL/.test(upper);
            const hasDefault = /DEFAULT\s/.test(upper);
            return hasNull || hasDefault;
        },
        type: "ADD_COLUMN",
        risk: "safe",
        description: "添加列操作",
    },
    {
        test: (upper) => /INSERT\s+INTO/.test(upper),
        type: "INSERT",
        risk: "safe",
        description: "插入数据操作",
    },
    {
        test: (upper) => /COMMENT\s+ON/.test(upper),
        type: "COMMENT",
        risk: "safe",
        description: "添加注释操作",
    },
    {
        test: (upper) => {
            // ALTER TABLE ... ADD COLUMN ... DEFAULT（安全变体）
            return /ALTER\s+TABLE/.test(upper) && /ADD\s+COLUMN/.test(upper) && /DEFAULT\s/.test(upper);
        },
        type: "ADD_COLUMN_DEFAULT",
        risk: "safe",
        description: "添加带默认值的列",
    },
];
// 合并所有规则，按优先级排列（critical → warning → safe），每行匹配到第一条规则即停止
const ALL_RULES = [...CRITICAL_RULES, ...WARNING_RULES, ...SAFE_RULES];
// ── 公共 API ──
/**
 * 分析 SQL 迁移脚本 — 逐行匹配规则，生成风险评级、语句列表和回滚建议。
 * @param content - SQL 迁移文件内容
 * @param filename - 文件名（用于结果标识）
 * @returns 迁移分析结果，包含风险等级(critical/warning/safe)、语句列表、回滚建议和中文摘要
 */
export function analyzeMigration(content, filename) {
    debug("迁移守卫", `开始分析 ${filename}`);
    const lines = content.split("\n");
    const statements = [];
    const seenRollbackSuggestions = new Set();
    if (lines.length === 0) {
        debug("迁移守卫", "文件内容为空", filename);
    }
    for (let i = 0; i < lines.length; i++) {
        const raw = lines[i].trim();
        // 跳过空行和纯注释行
        if (raw === "" || raw.startsWith("--"))
            continue;
        const upper = raw.toUpperCase();
        // 按优先级顺序尝试匹配规则（critical → warning → safe），首条命中即终止
        for (const rule of ALL_RULES) {
            if (rule.test(upper, raw, lines, i)) {
                const table = extractTableFrom(upper);
                statements.push({
                    line: i + 1,
                    type: rule.type,
                    table,
                    risk: rule.risk,
                    description: rule.description,
                });
                // 收集唯一的回滚建议
                const suggestion = ROLLBACK_SUGGESTIONS[rule.type];
                if (suggestion) {
                    seenRollbackSuggestions.add(suggestion);
                }
                // 每行仅匹配第一条规则
                break;
            }
        }
    }
    // 确定整体风险等级: 有 critical 则为 critical，有 warning 则为 warning，否则 safe
    const hasCritical = statements.some((s) => s.risk === "critical");
    const hasWarning = statements.some((s) => s.risk === "warning");
    if (hasCritical)
        debug("迁移守卫", `检测到高风险语句，请人工审核 ${filename}`);
    else if (hasWarning)
        debug("迁移守卫", `检测到警告级语句 ${filename}`);
    const risk_level = hasCritical
        ? "critical"
        : hasWarning
            ? "warning"
            : "safe";
    // 按风险等级统计数量
    const criticalCount = statements.filter((s) => s.risk === "critical").length;
    const warningCount = statements.filter((s) => s.risk === "warning").length;
    const safeCount = statements.filter((s) => s.risk === "safe").length;
    // 生成中文摘要
    const summary = `检测到 ${statements.length} 条语句：${criticalCount} 条高风险，${warningCount} 条警告，${safeCount} 条安全`;
    // 回滚建议按原始出现顺序排列，仅保留非安全操作的唯一建议
    const rollbackSuggestions = statements
        .filter((s) => s.risk !== "safe" && ROLLBACK_SUGGESTIONS[s.type])
        .reduce((acc, s) => {
        const text = ROLLBACK_SUGGESTIONS[s.type];
        if (text && !acc.includes(text))
            acc.push(text);
        return acc;
    }, []);
    debug("迁移守卫", `分析完成 ${filename} — ${summary}`);
    return {
        file: filename,
        risk_level,
        statements,
        rollback_suggestions: rollbackSuggestions,
        summary,
    };
}
//# sourceMappingURL=migration_guard.js.map