const SOURCE_STAGES = ['metadata', 'lexical', 'memory', 'vector', 'graph', 'worktree'];
export class SessionReplayService {
    store;
    constructor(store) {
        this.store = store;
    }
    async writeReplay(bundle) {
        await this.store.writeSessionReplay({
            ...bundle,
            recordedAt: bundle.recordedAt ?? new Date().toISOString(),
        });
    }
    async readReplay(sessionId) {
        return this.store.readSessionReplay(sessionId);
    }
}
export function sessionReplayFromContextPack(sessionId, pack) {
    if (!pack.debug || !pack.contextFit) {
        return undefined;
    }
    const stages = new Map(pack.debug.stages.map((stage) => [stage.name, stage.candidates]));
    const sourceCandidates = {};
    for (const stage of SOURCE_STAGES) {
        sourceCandidates[stage] = (stages.get(stage) ?? []).map(toReplayCandidate);
    }
    const fusionCandidates = stages.get('fusion') ?? [];
    const fusionOrder = fusionCandidates.length > 0
        ? fusionCandidates.map((candidate, index) => ({
            id: candidate.knowledgeId,
            rank: candidate.rank || index + 1,
            score: scoreForCandidate(candidate),
        }))
        : pack.sections
            .flatMap((section) => section.items)
            .map((item, index) => ({
            id: item.knowledgeId,
            rank: index + 1,
            score: item.finalScore,
        }));
    return {
        sessionId,
        recordedAt: new Date().toISOString(),
        classifier: pack.classified,
        sourceCandidates,
        fusionOrder,
        rerankDeltas: rerankDeltas(pack),
        adjustments: (pack.debug.suppressionEvents ?? []).map((event) => ({
            id: event.knowledgeId,
            reason: event.reason,
            delta: event.deltaScore,
        })),
        contextFit: pack.contextFit,
        pack: {
            essential: sectionIds(pack, 'essential'),
            supporting: sectionIds(pack, 'supporting'),
            optional: sectionIds(pack, 'optional'),
        },
        timings: {
            totalMs: pack.debug.timingsMs.total ?? 0,
            stageMs: pack.debug.timingsMs,
        },
    };
}
export function stripReplayDebug(pack) {
    if (!pack.debug) {
        return pack;
    }
    const { debug: _debug, ...rest } = pack;
    return rest;
}
function toReplayCandidate(candidate) {
    return {
        id: candidate.knowledgeId,
        rank: candidate.rank,
        title: candidate.title,
        source: candidate.source,
        score: scoreForCandidate(candidate),
    };
}
function scoreForCandidate(candidate) {
    return candidate.finalScore ?? candidate.rerankScore ?? candidate.fusedScore ?? candidate.rawScore ?? 0;
}
function rerankDeltas(pack) {
    if (pack.debug?.fusionBreakdown?.length) {
        return pack.debug.fusionBreakdown.map((breakdown) => ({
            id: breakdown.knowledgeId,
            before: breakdown.fusedScore,
            after: breakdown.rerankScore,
        }));
    }
    const reranked = pack.debug?.stages.find((stage) => stage.name === 'rerank')?.candidates ?? [];
    return reranked
        .filter((candidate) => candidate.fusedScore !== undefined && candidate.rerankScore !== undefined)
        .map((candidate) => ({
        id: candidate.knowledgeId,
        before: candidate.fusedScore ?? 0,
        after: candidate.rerankScore ?? 0,
    }));
}
function sectionIds(pack, sectionName) {
    return (pack.sections.find((section) => section.name === sectionName)?.items ?? [])
        .map((item) => ({ id: item.knowledgeId }));
}
