"use strict";
/**
 * Data Aggregator for Claude Code Usage Analytics
 *
 * Aggregates raw JSONL entries into daily, monthly, and session summaries.
 * Uses model-pricing.ts for cost calculations.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadAllUsageData = exports.loadSessionData = exports.loadMonthlyUsageData = exports.loadHourlyUsageData = exports.loadDailyUsageData = exports.aggregateSessionUsage = exports.aggregateMonthlyUsage = exports.aggregateHourlyUsage = exports.aggregateDailyUsage = void 0;
const model_pricing_1 = require("../model-pricing");
const model_identity_1 = require("./model-identity");
// ============================================================================
// HELPER FUNCTIONS
// ============================================================================
/** Extract YYYY-MM-DD from ISO timestamp */
function extractDate(timestamp) {
    return timestamp.slice(0, 10);
}
/** Extract YYYY-MM from ISO timestamp */
function extractMonth(timestamp) {
    return timestamp.slice(0, 7);
}
/** Extract YYYY-MM-DD HH:00 from ISO timestamp */
function extractHour(timestamp) {
    const date = timestamp.slice(0, 10);
    const hour = timestamp.slice(11, 13) || '00';
    return `${date} ${hour}:00`;
}
/** Create model breakdown from accumulated data */
function createModelBreakdown(modelName, provider, inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens) {
    const cost = (0, model_pricing_1.calculateCost)({ inputTokens, outputTokens, cacheCreationTokens, cacheReadTokens }, modelName, { provider });
    return {
        modelName,
        ...(provider && { provider }),
        inputTokens,
        outputTokens,
        cacheCreationTokens,
        cacheReadTokens,
        cost,
    };
}
function getEntryProvider(entry) {
    return (0, model_identity_1.normalizeUsageProvider)(entry.target);
}
function getEntryModelKey(entry) {
    return `${getEntryProvider(entry) ?? ''}\u0000${entry.model}`;
}
function createModelAccumulator(entry) {
    return {
        modelName: entry.model,
        provider: getEntryProvider(entry),
        inputTokens: 0,
        outputTokens: 0,
        cacheCreationTokens: 0,
        cacheReadTokens: 0,
    };
}
// ============================================================================
// DAILY AGGREGATION
// ============================================================================
/**
 * Aggregate raw entries into daily usage summaries
 * Groups by date (YYYY-MM-DD), calculates costs per model
 */
function aggregateDailyUsage(entries, source = 'custom-parser') {
    // Group entries by date
    const byDate = new Map();
    for (const entry of entries) {
        const date = extractDate(entry.timestamp);
        const existing = byDate.get(date) || [];
        existing.push(entry);
        byDate.set(date, existing);
    }
    // Build daily summaries
    const dailyUsage = [];
    for (const [date, dateEntries] of byDate) {
        // Aggregate by model
        const modelMap = new Map();
        let totalInput = 0;
        let totalOutput = 0;
        let totalCacheCreation = 0;
        let totalCacheRead = 0;
        for (const entry of dateEntries) {
            const modelKey = getEntryModelKey(entry);
            const acc = modelMap.get(modelKey) || createModelAccumulator(entry);
            acc.inputTokens += entry.inputTokens;
            acc.outputTokens += entry.outputTokens;
            acc.cacheCreationTokens += entry.cacheCreationTokens;
            acc.cacheReadTokens += entry.cacheReadTokens;
            modelMap.set(modelKey, acc);
            totalInput += entry.inputTokens;
            totalOutput += entry.outputTokens;
            totalCacheCreation += entry.cacheCreationTokens;
            totalCacheRead += entry.cacheReadTokens;
        }
        // Build model breakdowns
        const modelBreakdowns = [];
        let totalCost = 0;
        for (const acc of modelMap.values()) {
            const breakdown = createModelBreakdown(acc.modelName, acc.provider, acc.inputTokens, acc.outputTokens, acc.cacheCreationTokens, acc.cacheReadTokens);
            modelBreakdowns.push(breakdown);
            totalCost += breakdown.cost;
        }
        // Sort breakdowns by cost descending
        modelBreakdowns.sort((a, b) => b.cost - a.cost);
        dailyUsage.push({
            date,
            source,
            inputTokens: totalInput,
            outputTokens: totalOutput,
            cacheCreationTokens: totalCacheCreation,
            cacheReadTokens: totalCacheRead,
            cost: totalCost,
            totalCost,
            modelsUsed: (0, model_identity_1.getModelsUsed)(modelBreakdowns),
            modelBreakdowns,
        });
    }
    // Sort by date descending (most recent first)
    dailyUsage.sort((a, b) => b.date.localeCompare(a.date));
    return dailyUsage;
}
exports.aggregateDailyUsage = aggregateDailyUsage;
// ============================================================================
// HOURLY AGGREGATION
// ============================================================================
/**
 * Aggregate raw entries into hourly usage summaries
 * Groups by hour (YYYY-MM-DD HH:00), calculates costs per model
 */
function aggregateHourlyUsage(entries, source = 'custom-parser') {
    // Group entries by hour
    const byHour = new Map();
    for (const entry of entries) {
        const hour = extractHour(entry.timestamp);
        const existing = byHour.get(hour) || [];
        existing.push(entry);
        byHour.set(hour, existing);
    }
    // Build hourly summaries
    const hourlyUsage = [];
    for (const [hour, hourEntries] of byHour) {
        // Aggregate by model
        const modelMap = new Map();
        let totalInput = 0;
        let totalOutput = 0;
        let totalCacheCreation = 0;
        let totalCacheRead = 0;
        for (const entry of hourEntries) {
            const modelKey = getEntryModelKey(entry);
            const acc = modelMap.get(modelKey) || createModelAccumulator(entry);
            acc.inputTokens += entry.inputTokens;
            acc.outputTokens += entry.outputTokens;
            acc.cacheCreationTokens += entry.cacheCreationTokens;
            acc.cacheReadTokens += entry.cacheReadTokens;
            modelMap.set(modelKey, acc);
            totalInput += entry.inputTokens;
            totalOutput += entry.outputTokens;
            totalCacheCreation += entry.cacheCreationTokens;
            totalCacheRead += entry.cacheReadTokens;
        }
        // Build model breakdowns
        const modelBreakdowns = [];
        let totalCost = 0;
        for (const acc of modelMap.values()) {
            const breakdown = createModelBreakdown(acc.modelName, acc.provider, acc.inputTokens, acc.outputTokens, acc.cacheCreationTokens, acc.cacheReadTokens);
            modelBreakdowns.push(breakdown);
            totalCost += breakdown.cost;
        }
        // Sort breakdowns by cost descending
        modelBreakdowns.sort((a, b) => b.cost - a.cost);
        hourlyUsage.push({
            hour,
            source,
            inputTokens: totalInput,
            outputTokens: totalOutput,
            cacheCreationTokens: totalCacheCreation,
            cacheReadTokens: totalCacheRead,
            cost: totalCost,
            totalCost,
            modelsUsed: (0, model_identity_1.getModelsUsed)(modelBreakdowns),
            modelBreakdowns,
            requestCount: hourEntries.length,
        });
    }
    // Sort by hour descending (most recent first)
    hourlyUsage.sort((a, b) => b.hour.localeCompare(a.hour));
    return hourlyUsage;
}
exports.aggregateHourlyUsage = aggregateHourlyUsage;
// ============================================================================
// MONTHLY AGGREGATION
// ============================================================================
/**
 * Aggregate raw entries into monthly usage summaries
 * Groups by month (YYYY-MM), calculates costs per model
 */
function aggregateMonthlyUsage(entries, source = 'custom-parser') {
    // Group entries by month
    const byMonth = new Map();
    for (const entry of entries) {
        const month = extractMonth(entry.timestamp);
        const existing = byMonth.get(month) || [];
        existing.push(entry);
        byMonth.set(month, existing);
    }
    // Build monthly summaries
    const monthlyUsage = [];
    for (const [month, monthEntries] of byMonth) {
        // Aggregate by model
        const modelMap = new Map();
        let totalInput = 0;
        let totalOutput = 0;
        let totalCacheCreation = 0;
        let totalCacheRead = 0;
        for (const entry of monthEntries) {
            const modelKey = getEntryModelKey(entry);
            const acc = modelMap.get(modelKey) || createModelAccumulator(entry);
            acc.inputTokens += entry.inputTokens;
            acc.outputTokens += entry.outputTokens;
            acc.cacheCreationTokens += entry.cacheCreationTokens;
            acc.cacheReadTokens += entry.cacheReadTokens;
            modelMap.set(modelKey, acc);
            totalInput += entry.inputTokens;
            totalOutput += entry.outputTokens;
            totalCacheCreation += entry.cacheCreationTokens;
            totalCacheRead += entry.cacheReadTokens;
        }
        // Build model breakdowns
        const modelBreakdowns = [];
        let totalCost = 0;
        for (const acc of modelMap.values()) {
            const breakdown = createModelBreakdown(acc.modelName, acc.provider, acc.inputTokens, acc.outputTokens, acc.cacheCreationTokens, acc.cacheReadTokens);
            modelBreakdowns.push(breakdown);
            totalCost += breakdown.cost;
        }
        // Sort breakdowns by cost descending
        modelBreakdowns.sort((a, b) => b.cost - a.cost);
        monthlyUsage.push({
            month,
            source,
            inputTokens: totalInput,
            outputTokens: totalOutput,
            cacheCreationTokens: totalCacheCreation,
            cacheReadTokens: totalCacheRead,
            totalCost,
            modelsUsed: (0, model_identity_1.getModelsUsed)(modelBreakdowns),
            modelBreakdowns,
        });
    }
    // Sort by month descending (most recent first)
    monthlyUsage.sort((a, b) => b.month.localeCompare(a.month));
    return monthlyUsage;
}
exports.aggregateMonthlyUsage = aggregateMonthlyUsage;
// ============================================================================
// SESSION AGGREGATION
// ============================================================================
/**
 * Aggregate raw entries into session usage summaries
 * Groups by sessionId, tracks last activity and versions
 */
function aggregateSessionUsage(entries, source = 'custom-parser') {
    // Group entries by sessionId
    const bySession = new Map();
    for (const entry of entries) {
        if (!entry.sessionId)
            continue;
        const existing = bySession.get(entry.sessionId) || [];
        existing.push(entry);
        bySession.set(entry.sessionId, existing);
    }
    // Build session summaries
    const sessionUsage = [];
    for (const [sessionId, sessionEntries] of bySession) {
        const orderedEntries = [...sessionEntries].sort((a, b) => a.timestamp.localeCompare(b.timestamp));
        // Aggregate by model
        const modelMap = new Map();
        const versions = new Set();
        let totalInput = 0;
        let totalOutput = 0;
        let totalCacheCreation = 0;
        let totalCacheRead = 0;
        let lastActivity = '';
        let projectPath = '';
        let target;
        for (const entry of orderedEntries) {
            const modelKey = getEntryModelKey(entry);
            const acc = modelMap.get(modelKey) || createModelAccumulator(entry);
            acc.inputTokens += entry.inputTokens;
            acc.outputTokens += entry.outputTokens;
            acc.cacheCreationTokens += entry.cacheCreationTokens;
            acc.cacheReadTokens += entry.cacheReadTokens;
            modelMap.set(modelKey, acc);
            totalInput += entry.inputTokens;
            totalOutput += entry.outputTokens;
            totalCacheCreation += entry.cacheCreationTokens;
            totalCacheRead += entry.cacheReadTokens;
            // Track latest timestamp
            if (entry.timestamp > lastActivity) {
                lastActivity = entry.timestamp;
            }
            // Track versions
            if (entry.version) {
                versions.add(entry.version);
            }
            // Use project path from entry
            if (entry.projectPath) {
                projectPath = entry.projectPath;
            }
            if (entry.target) {
                target = entry.target;
            }
        }
        // Build model breakdowns
        const modelBreakdowns = [];
        let totalCost = 0;
        for (const acc of modelMap.values()) {
            const breakdown = createModelBreakdown(acc.modelName, acc.provider, acc.inputTokens, acc.outputTokens, acc.cacheCreationTokens, acc.cacheReadTokens);
            modelBreakdowns.push(breakdown);
            totalCost += breakdown.cost;
        }
        // Sort breakdowns by cost descending
        modelBreakdowns.sort((a, b) => b.cost - a.cost);
        sessionUsage.push({
            sessionId,
            projectPath,
            inputTokens: totalInput,
            outputTokens: totalOutput,
            cacheCreationTokens: totalCacheCreation,
            cacheReadTokens: totalCacheRead,
            cost: totalCost,
            totalCost,
            lastActivity,
            versions: Array.from(versions),
            modelsUsed: (0, model_identity_1.getModelsUsed)(modelBreakdowns),
            modelBreakdowns,
            source,
            target,
        });
    }
    // Sort by last activity descending (most recent first)
    sessionUsage.sort((a, b) => b.lastActivity.localeCompare(a.lastActivity));
    return sessionUsage;
}
exports.aggregateSessionUsage = aggregateSessionUsage;
// ============================================================================
// MAIN DATA LOADER (drop-in replacement for better-ccusage)
// ============================================================================
const jsonl_parser_1 = require("../jsonl-parser");
/**
 * Load daily usage data (replaces better-ccusage loadDailyUsageData)
 */
async function loadDailyUsageData(options) {
    const entries = await (0, jsonl_parser_1.scanProjectsDirectory)(options);
    return aggregateDailyUsage(entries);
}
exports.loadDailyUsageData = loadDailyUsageData;
/**
 * Load hourly usage data for today's chart
 */
async function loadHourlyUsageData(options) {
    const entries = await (0, jsonl_parser_1.scanProjectsDirectory)(options);
    return aggregateHourlyUsage(entries);
}
exports.loadHourlyUsageData = loadHourlyUsageData;
/**
 * Load monthly usage data (replaces better-ccusage loadMonthlyUsageData)
 */
async function loadMonthlyUsageData(options) {
    const entries = await (0, jsonl_parser_1.scanProjectsDirectory)(options);
    return aggregateMonthlyUsage(entries);
}
exports.loadMonthlyUsageData = loadMonthlyUsageData;
/**
 * Load session data (replaces better-ccusage loadSessionData)
 */
async function loadSessionData(options) {
    const entries = await (0, jsonl_parser_1.scanProjectsDirectory)(options);
    return aggregateSessionUsage(entries);
}
exports.loadSessionData = loadSessionData;
/**
 * Load all usage data in a single pass (more efficient)
 */
async function loadAllUsageData(options) {
    const entries = await (0, jsonl_parser_1.scanProjectsDirectory)(options);
    return {
        daily: aggregateDailyUsage(entries),
        hourly: aggregateHourlyUsage(entries),
        monthly: aggregateMonthlyUsage(entries),
        session: aggregateSessionUsage(entries),
    };
}
exports.loadAllUsageData = loadAllUsageData;
//# sourceMappingURL=data-aggregator.js.map