import path from "node:path";
import { readFile } from "node:fs/promises";
import { nowIso, readJsonl, sanitizeText } from "../../shared/index.js";
import { getRun, listTasks, runDir } from "../run-state/store.js";
export async function buildRunTelemetrySummary(store, runId) {
    const dir = runDir(store, runId);
    const [run, tasks, events, agentCalls, toolCalls, evidenceText, finalReportText] = await Promise.all([
        getRun(store, runId),
        listTasks(store, runId),
        readJsonl(path.join(dir, "events.jsonl")),
        readJsonl(path.join(dir, "agent_calls.jsonl")),
        readJsonl(path.join(dir, "tool_calls.jsonl")),
        readOptionalText(path.join(dir, "evidence.md")),
        readOptionalText(path.join(dir, "final_report.md")),
    ]);
    if (!run)
        throw new Error(`SEED run not found: ${runId}`);
    const taskList = tasks;
    const latestToolCalls = latestById(toolCalls, (call) => call.tool_call_id);
    const latestAgentCalls = latestById(agentCalls, (call) => call.agent_call_id);
    const taskEvidenceRefs = unique(taskList.flatMap((task) => task.evidence_refs).filter(isEvidenceRef));
    const toolEvidenceRefs = unique(latestToolCalls.flatMap((call) => call.evidence_refs).filter(isEvidenceRef));
    const agentEvidenceRefs = unique(latestAgentCalls.flatMap((call) => call.evidence_refs).filter(isEvidenceRef));
    const finalReportRefs = unique(matchEvidenceRefs(finalReportText));
    const referenced = unique([...taskEvidenceRefs, ...toolEvidenceRefs, ...agentEvidenceRefs, ...finalReportRefs]);
    const ledgerRefs = matchEvidenceAnchors(evidenceText);
    const modelAttempts = latestAgentCalls.flatMap((call) => call.model_attempts ?? []);
    const taskStatusCounts = countBy(taskList.map((task) => task.status));
    const toolStatusCounts = countBy(latestToolCalls.map((call) => call.status));
    const agentStatusCounts = countBy(latestAgentCalls.map((call) => call.status));
    const blockedTasks = taskStatusCounts.blocked ?? 0;
    const failedTools = toolStatusCounts.failed ?? 0;
    const failedAgents = agentStatusCounts.failed ?? 0;
    const openTasks = taskList.filter((task) => !["completed", "cancelled"].includes(task.status)).length;
    const finalReportHasEvidenceRefs = finalReportRefs.length > 0;
    const finalReportCoversTaskEvidence = taskEvidenceRefs.every((ref) => finalReportRefs.includes(ref));
    const warnings = qualityWarnings({
        openTasks,
        blockedTasks,
        failedTools,
        failedAgents,
        finalReportText,
        finalReportHasEvidenceRefs,
        taskEvidenceRefs,
        finalReportCoversTaskEvidence,
    });
    return {
        schema_version: 1,
        generated_at: nowIso(),
        run: {
            run_id: run.run_id,
            status: run.status,
            created_at: run.created_at,
            updated_at: run.updated_at,
            completed_at: run.completed_at,
            duration_ms: durationMs(run.created_at, run.completed_at ?? run.updated_at),
            professor_goal_summary: sanitizeText(run.professor_goal).slice(0, 240),
        },
        tasks: {
            total: taskList.length,
            by_status: taskStatusCounts,
            open: openTasks,
            blocked: blockedTasks,
            completed: taskStatusCounts.completed ?? 0,
            with_evidence: taskList.filter((task) => task.evidence_refs.length > 0).length,
            acceptance_criteria_total: taskList.reduce((sum, task) => sum + task.acceptance_criteria.length, 0),
        },
        tools: {
            total: latestToolCalls.length,
            by_status: toolStatusCounts,
            by_tool: countBy(latestToolCalls.map((call) => call.tool_name)),
            failed: failedTools,
            with_evidence: latestToolCalls.filter((call) => call.evidence_refs.length > 0).length,
        },
        agents: {
            total: latestAgentCalls.length,
            by_status: agentStatusCounts,
            by_target_agent: countBy(latestAgentCalls.map((call) => call.target_agent)),
            by_mode: countBy(latestAgentCalls.map((call) => call.mode)),
            failed: failedAgents,
            model_attempts: {
                total: modelAttempts.length,
                by_status: countBy(modelAttempts.map((attempt) => attempt.status)),
                by_model: countBy(modelAttempts.map((attempt) => modelLabel(attempt.model ?? attempt.modelID))),
                fallback_attempts: modelAttempts.filter((attempt) => attempt.source === "fallback").length,
            },
        },
        events: {
            total: events.length,
            by_type: countBy(events.map((event) => event.type)),
            latest: events.slice(-8).map((event) => ({
                timestamp: event.timestamp,
                type: event.type,
                actor: event.actor,
                summary: event.summary,
            })),
        },
        evidence: {
            ledger_count: ledgerRefs.length,
            referenced_count: referenced.length,
            referenced,
            final_report_refs: finalReportRefs,
            task_evidence_refs: taskEvidenceRefs,
            final_report_covers_task_evidence: finalReportCoversTaskEvidence,
        },
        quality_gates: {
            has_final_report: finalReportText.trim().length > 0,
            final_report_has_evidence_refs: finalReportHasEvidenceRefs,
            no_open_tasks: openTasks === 0,
            no_blocked_tasks: blockedTasks === 0,
            no_failed_tools: failedTools === 0,
            no_failed_agent_calls: failedAgents === 0,
            warnings,
        },
    };
}
function qualityWarnings(input) {
    const warnings = [];
    if (input.openTasks > 0)
        warnings.push(`${input.openTasks} task(s) are still open.`);
    if (input.blockedTasks > 0)
        warnings.push(`${input.blockedTasks} task(s) are blocked.`);
    if (input.failedTools > 0)
        warnings.push(`${input.failedTools} tool call(s) failed.`);
    if (input.failedAgents > 0)
        warnings.push(`${input.failedAgents} agent call(s) failed.`);
    if (!input.finalReportText.trim())
        warnings.push("final_report.md is empty or missing.");
    if (input.taskEvidenceRefs.length > 0 && !input.finalReportHasEvidenceRefs) {
        warnings.push("Final report does not cite any evidence anchors.");
    }
    else if (!input.finalReportCoversTaskEvidence) {
        warnings.push("Final report does not cite every task evidence anchor.");
    }
    return warnings;
}
function countBy(values) {
    const counts = {};
    for (const value of values) {
        const key = value || "unknown";
        counts[key] = (counts[key] ?? 0) + 1;
    }
    return counts;
}
function latestById(values, keyFor) {
    const byId = new Map();
    for (const value of values)
        byId.set(keyFor(value), value);
    return [...byId.values()];
}
function unique(values) {
    return [...new Set(values.filter(Boolean))].sort();
}
function matchEvidenceAnchors(text) {
    return unique([...text.matchAll(/<a id="([^"]+)"><\/a>/g)].map((match) => `evidence.md#${match[1]}`));
}
function matchEvidenceRefs(text) {
    return unique([...text.matchAll(/evidence\.md#[A-Za-z0-9_.-]+/g)].map((match) => match[0]));
}
function isEvidenceRef(ref) {
    return /^evidence\.md#[A-Za-z0-9_.-]+$/.test(ref);
}
function modelLabel(model) {
    return model?.trim() || "unknown";
}
function durationMs(start, end) {
    const startMs = Date.parse(start);
    const endMs = Date.parse(end);
    if (!Number.isFinite(startMs) || !Number.isFinite(endMs))
        return undefined;
    return Math.max(0, endMs - startMs);
}
async function readOptionalText(file) {
    try {
        return await readFile(file, "utf8");
    }
    catch (error) {
        if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT")
            return "";
        throw error;
    }
}
//# sourceMappingURL=index.js.map