/**
 * pipeline/baseline.ts
 *
 * Pure computation functions for managing historical baseline snapshots of
 * evaluation scores. All functions accept `rootDir` as their first parameter
 * and perform no process.env / process.argv access.
 */
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync, } from "fs";
import { join } from "path";
export function compareBaseline(dirs, baselineFile) {
    const { baselinesDir, scoreSummaryPath } = dirs;
    if (!existsSync(scoreSummaryPath)) {
        return {
            message: "No current score-summary.json found.",
            success: false,
        };
    }
    // Find baseline to compare against
    const baselines = listBaselines(baselinesDir);
    if (baselines.length === 0) {
        return {
            message: "No baselines saved yet. Run 'pnpm baseline:save' first.",
            success: false,
        };
    }
    const targetFile = baselineFile ?? baselines[0].filename;
    const baselinePath = join(baselinesDir, targetFile);
    if (!existsSync(baselinePath)) {
        return {
            message: `Baseline file not found: ${targetFile}`,
            success: false,
        };
    }
    const current = JSON.parse(readFileSync(scoreSummaryPath, "utf-8"));
    const baseline = JSON.parse(readFileSync(baselinePath, "utf-8"));
    const baselineMap = new Map(baseline.scores.map((s) => [s.feature, s.totalScore]));
    const baselineCostMap = new Map(baseline.scores.map((s) => [s.feature, s.totalCost ?? 0]));
    const comparisons = current.scores.map((s) => {
        const baseScore = baselineMap.get(s.feature) ?? 0;
        const currentCost = s.totalCost ?? 0;
        const baseCost = baselineCostMap.get(s.feature) ?? 0;
        return {
            baseline: baseScore,
            costBaseline: baseCost > 0 ? baseCost : undefined,
            costCurrent: currentCost > 0 ? currentCost : undefined,
            costDelta: currentCost > 0 || baseCost > 0 ? currentCost - baseCost : undefined,
            current: s.totalScore,
            delta: s.totalScore - baseScore,
            feature: s.feature,
        };
    });
    // Check for areas in baseline but not in current
    for (const [feature, score] of baselineMap) {
        if (!comparisons.find((c) => c.feature === feature)) {
            comparisons.push({
                baseline: score,
                current: 0,
                delta: -score,
                feature,
            });
        }
    }
    comparisons.sort((a, b) => b.delta - a.delta);
    const overallDelta = Math.round(current.overall.avgScore) - Math.round(baseline.overall.avgScore);
    return {
        comparisons,
        message: `Compared against ${targetFile}`,
        overallDelta,
        success: true,
    };
}
// ---------------------------------------------------------------------------
// List
// ---------------------------------------------------------------------------
export function listBaselines(baselinesDir) {
    if (!existsSync(baselinesDir)) {
        return [];
    }
    const files = readdirSync(baselinesDir)
        .filter((f) => f.endsWith(".json"))
        .sort()
        .reverse(); // Newest first
    return files.map((filename) => {
        const raw = readFileSync(join(baselinesDir, filename), "utf-8");
        const data = JSON.parse(raw);
        return {
            areaCount: data.scores.length,
            avgScore: Math.round(data.overall.avgScore),
            filename,
            graderCost: data.overall.cost?.graderTotal,
            tag: data.baselineMeta?.tag,
            timestamp: data.timestamp,
            totalCost: data.overall.cost?.total,
        };
    });
}
// ---------------------------------------------------------------------------
// Save
// ---------------------------------------------------------------------------
export function saveBaseline(dirs, tag) {
    const { baselinesDir, scoreSummaryPath } = dirs;
    if (!existsSync(scoreSummaryPath)) {
        return {
            message: "No score-summary.json found. Run 'pnpm calculate-scores' first.",
            success: false,
        };
    }
    const raw = readFileSync(scoreSummaryPath, "utf-8");
    const summary = JSON.parse(raw);
    mkdirSync(baselinesDir, { recursive: true });
    // Generate filename: YYYY-MM-DD_HHmmss[_tag].json
    const now = new Date();
    const datePart = now
        .toISOString()
        .slice(0, 19)
        .replace(/[T:]/g, "_")
        .replace(/-/g, "");
    const tagPart = tag
        ? `_${tag.replace(/[^a-z0-9-]/gi, "-").toLowerCase()}`
        : "";
    const filename = `${datePart}${tagPart}.json`;
    const baseline = {
        ...summary,
        baselineMeta: {
            savedAt: now.toISOString(),
            // oxlint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- empty string tag should be treated as no tag
            tag: tag || undefined,
        },
    };
    writeFileSync(join(baselinesDir, filename), JSON.stringify(baseline, null, 2));
    return {
        message: `Saved baseline to ${join(baselinesDir, filename)} (avg: ${Math.round(summary.overall.avgScore)}, ${summary.scores.length} areas)`,
        success: true,
    };
}
