/**
 * 逃逸报告 — 结构化记录抽检失败、误伤、工具故障。
 * P2-3 范围: 只落盘记录，不自动降级，不改 capability 状态。
 * 存储: JSON 数组文件，原子写入，路径绑定 stateDir。
 */
import fs from "node:fs";
import path from "node:path";
import { debug } from "../core/logger.js";
import { safeJsonParse } from "../core/helpers.js";
/** 所有可能的逃逸类型 */
const ALL_ESCAPE_TYPES = [
    "rule_gap",
    "weak_test",
    "bad_evidence",
    "ai_escape",
    "human_miss",
    "tool_bug",
    "false_positive",
];
/** 所有可能的能力处置动作 */
const ALL_CAPABILITY_ACTIONS = [
    "keep",
    "downgrade",
    "disable",
    "promote_blocked",
];
/** 创建按逃逸类型统计的空记录 */
function emptyByType() {
    return Object.fromEntries(ALL_ESCAPE_TYPES.map((t) => [t, 0]));
}
/** 创建按处置动作统计的空记录 */
function emptyByAction() {
    return Object.fromEntries(ALL_CAPABILITY_ACTIONS.map((a) => [a, 0]));
}
/** 深拷贝逃逸报告 */
function deepCopy(report) {
    return { ...report };
}
/** 逃逸报告存储 — 管理逃逸报告的持久化和查询 */
export class EscapeReportStore {
    filePath;
    reports = [];
    loaded = false;
    /**
     * 创建逃逸报告存储实例。
     * @param stateDir - 状态目录路径，报告数据将存储在此目录下
     */
    constructor(stateDir) {
        this.filePath = path.join(stateDir, "escape-reports.json");
        if (!fs.existsSync(stateDir)) {
            fs.mkdirSync(stateDir, { recursive: true });
        }
        debug("逃逸报告", "初始化完成，数据路径: " + this.filePath);
    }
    /** 确保数据已从磁盘加载 */
    ensureLoaded() {
        if (this.loaded)
            return;
        this.loaded = true;
        try {
            const data = fs.readFileSync(this.filePath, "utf-8");
            this.reports = safeJsonParse(data) ?? [];
        }
        catch {
            this.reports = [];
        }
    }
    /** 持久化当前数据到磁盘（原子写入） */
    persist() {
        const tmpPath = `${this.filePath}.tmp`;
        fs.writeFileSync(tmpPath, JSON.stringify(this.reports, null, 2));
        fs.renameSync(tmpPath, this.filePath);
    }
    /**
     * 追加逃逸报告并持久化。
     * @param report - 要追加的逃逸报告
     */
    append(report) {
        this.ensureLoaded();
        this.reports.push(deepCopy(report));
        this.persist();
        debug("逃逸报告", `追加报告 escape_id=${report.escape_id}, 类型=${report.failure_type}, 策略=${report.policy_id}`);
    }
    /**
     * 查询逃逸报告列表，支持按失败类型、策略 ID 和任务 ID 过滤。
     * @param filter - 可选过滤条件
     * @param filter.failure_type - 按失败类型过滤
     * @param filter.policy_id - 按策略 ID 过滤
     * @param filter.task_id - 按任务 ID 过滤
     * @returns 匹配的逃逸报告列表（深拷贝）
     */
    list(filter) {
        this.ensureLoaded();
        let result = this.reports;
        if (filter?.failure_type) {
            result = result.filter((r) => r.failure_type === filter.failure_type);
        }
        if (filter?.policy_id) {
            result = result.filter((r) => r.policy_id === filter.policy_id);
        }
        if (filter?.task_id) {
            result = result.filter((r) => r.task_id === filter.task_id);
        }
        return result.map(deepCopy);
    }
    /**
     * 获取逃逸报告统计信息。
     * @returns 包含总数和按类型/动作分布的统计信息
     */
    stats() {
        this.ensureLoaded();
        const by_type = emptyByType();
        const by_action = emptyByAction();
        for (const r of this.reports) {
            by_type[r.failure_type]++;
            by_action[r.capability_action]++;
        }
        return { total: this.reports.length, by_type, by_action };
    }
    /**
     * 清空所有逃逸报告并持久化。
     */
    clear() {
        this.reports = [];
        this.loaded = true;
        this.persist();
        debug("逃逸报告", "已清空所有报告");
    }
    /**
     * 获取逃逸报告数据文件路径。
     * @returns 数据文件的绝对路径
     */
    getFilePath() {
        return this.filePath;
    }
}
//# sourceMappingURL=escape_report.js.map