// engine/spec-observability/metrics.ts — Aggregate usage data (SPEC-158)
// Computes hot specs, cold specs, tool matrix, and hot ACs from raw events.
function periodCutoff(period) {
    const now = Date.now();
    switch (period) {
        case 'day':
            return now - 24 * 60 * 60 * 1000;
        case 'week':
            return now - 7 * 24 * 60 * 60 * 1000;
        case 'month':
            return now - 30 * 24 * 60 * 60 * 1000;
        case 'all':
            return 0;
    }
}
export function filterByPeriod(events, period) {
    const cutoff = periodCutoff(period);
    return events.filter((e) => new Date(e.timestamp).getTime() >= cutoff);
}
// ---------------------------------------------------------------------------
// Per-spec aggregation
// ---------------------------------------------------------------------------
/**
 * Aggregate a flat event list into per-spec metrics.
 */
export function aggregateBySpec(events) {
    const bySpec = new Map();
    for (const event of events) {
        const existing = bySpec.get(event.specId) ?? [];
        existing.push(event);
        bySpec.set(event.specId, existing);
    }
    const results = [];
    for (const [specId, specEvents] of bySpec.entries()) {
        const toolMatrix = {};
        const acCounts = {};
        const toolsSet = new Set();
        let firstAccess = specEvents[0]?.timestamp ?? '';
        let lastAccess = specEvents[0]?.timestamp ?? '';
        for (const e of specEvents) {
            toolMatrix[e.toolName] = (toolMatrix[e.toolName] ?? 0) + 1;
            toolsSet.add(e.toolName);
            if (e.acRef) {
                acCounts[e.acRef] = (acCounts[e.acRef] ?? 0) + 1;
            }
            if (e.timestamp < firstAccess) {
                firstAccess = e.timestamp;
            }
            if (e.timestamp > lastAccess) {
                lastAccess = e.timestamp;
            }
        }
        const hotAcs = Object.entries(acCounts)
            .sort((a, b) => b[1] - a[1])
            .slice(0, 5)
            .map(([acRef, count]) => ({ acRef, count }));
        results.push({
            specId,
            totalAccesses: specEvents.length,
            toolsUsed: [...toolsSet],
            toolMatrix,
            hotAcs,
            firstAccessAt: firstAccess,
            lastAccessAt: lastAccess,
        });
    }
    return results.sort((a, b) => b.totalAccesses - a.totalAccesses);
}
// ---------------------------------------------------------------------------
// Top tools
// ---------------------------------------------------------------------------
function computeTopTools(events) {
    const counts = {};
    for (const e of events) {
        counts[e.toolName] = (counts[e.toolName] ?? 0) + 1;
    }
    return Object.entries(counts)
        .sort((a, b) => b[1] - a[1])
        .map(([toolName, count]) => ({ toolName, count }));
}
// ---------------------------------------------------------------------------
// Cold spec detection
// ---------------------------------------------------------------------------
/**
 * Identify spec IDs that are known but had zero accesses in the period.
 * `allKnownSpecIds` comes from the spec store (approved/implementing specs).
 */
function computeColdSpecs(accessedSpecIds, allKnownSpecIds) {
    return allKnownSpecIds.filter((id) => !accessedSpecIds.has(id)).sort();
}
// ---------------------------------------------------------------------------
// Full report builder
// ---------------------------------------------------------------------------
export function buildObservabilityReport(opts) {
    const { projectId, period, events, allKnownSpecIds = [], filterSpecId } = opts;
    const periodEvents = filterByPeriod(events, period);
    const scopedEvents = filterSpecId !== undefined
        ? periodEvents.filter((e) => e.specId === filterSpecId.toUpperCase())
        : periodEvents;
    const specMetrics = aggregateBySpec(scopedEvents);
    const accessedIds = new Set(specMetrics.map((m) => m.specId));
    const coldSpecs = filterSpecId !== undefined ? [] : computeColdSpecs(accessedIds, allKnownSpecIds);
    const topTools = computeTopTools(scopedEvents);
    const hotSpecs = specMetrics.slice(0, 10);
    return {
        projectId,
        period,
        generatedAt: new Date().toISOString(),
        totalEvents: scopedEvents.length,
        hotSpecs,
        coldSpecs,
        specMetrics,
        topTools,
    };
}
//# sourceMappingURL=metrics.js.map