/**
 * Session insights engine.
 *
 * Rich usage analytics from the stats tracker history.
 *
 * Provides:
 *   - Per-model cost and request breakdown
 *   - Daily activity trend (sparkline)
 *   - Top sessions by cost
 *   - Tool usage patterns
 *   - Cost projections and efficiency metrics
 */
import { loadStats } from './tracker.js';
import { OPUS_PRICING, MODEL_PRICING } from '../pricing.js';
import { formatTokens, formatUsd, shortModelName } from './format.js';
// ─── Generate Report ──────────────────────────────────────────────────────
export function generateInsights(days = 30) {
    const stats = loadStats();
    const now = Date.now();
    const windowStart = now - days * 24 * 60 * 60 * 1000;
    const windowHistory = stats.history.filter(r => r.timestamp >= windowStart);
    // Aggregate totals
    let totalCost = 0;
    let totalInput = 0;
    let totalOutput = 0;
    // Category totals — see InsightsReport.byCategory doc.
    let chatCost = 0;
    let mediaCost = 0;
    let sandboxCost = 0;
    let sandboxRequests = 0;
    const modelAgg = new Map();
    for (const r of windowHistory) {
        totalCost += r.costUsd;
        totalInput += r.inputTokens;
        totalOutput += r.outputTokens;
        // Categorize: modal/* always goes to sandbox; zero-token entries are
        // media (image/video/music recordUsage stores 0/0 tokens); rest = chat.
        if (r.model.startsWith('modal/')) {
            sandboxCost += r.costUsd;
            sandboxRequests++;
        }
        else if ((r.inputTokens + r.outputTokens) === 0) {
            mediaCost += r.costUsd;
        }
        else {
            chatCost += r.costUsd;
        }
        const existing = modelAgg.get(r.model) ?? {
            requests: 0,
            costUsd: 0,
            inputTokens: 0,
            outputTokens: 0,
            totalLatencyMs: 0,
        };
        existing.requests++;
        existing.costUsd += r.costUsd;
        existing.inputTokens += r.inputTokens;
        existing.outputTokens += r.outputTokens;
        existing.totalLatencyMs += r.latencyMs;
        modelAgg.set(r.model, existing);
    }
    // Build byModel array sorted by cost
    const byModel = [];
    for (const [model, agg] of modelAgg.entries()) {
        byModel.push({
            model,
            requests: agg.requests,
            costUsd: agg.costUsd,
            inputTokens: agg.inputTokens,
            outputTokens: agg.outputTokens,
            avgLatencyMs: agg.requests > 0 ? Math.round(agg.totalLatencyMs / agg.requests) : 0,
            percentOfTotal: totalCost > 0 ? (agg.costUsd / totalCost) * 100 : 0,
        });
    }
    byModel.sort((a, b) => b.costUsd - a.costUsd);
    // Daily activity
    const dailyMap = new Map();
    for (let i = 0; i < days; i++) {
        const d = new Date(now - i * 24 * 60 * 60 * 1000);
        const key = d.toISOString().slice(0, 10);
        dailyMap.set(key, { requests: 0, costUsd: 0 });
    }
    for (const r of windowHistory) {
        const key = new Date(r.timestamp).toISOString().slice(0, 10);
        const existing = dailyMap.get(key);
        if (existing) {
            existing.requests++;
            existing.costUsd += r.costUsd;
        }
    }
    const daily = Array.from(dailyMap.entries())
        .map(([date, v]) => ({ date, ...v }))
        .sort((a, b) => a.date.localeCompare(b.date));
    // Calculate savings vs Opus
    const opusCostPer1M = (OPUS_PRICING.input + OPUS_PRICING.output) / 2;
    const opusWouldCost = ((totalInput + totalOutput) / 1_000_000) * opusCostPer1M;
    const savedVsOpusUsd = Math.max(0, opusWouldCost - totalCost);
    // Projections
    const avgCostPerDay = days > 0 ? totalCost / days : 0;
    const projections = {
        avgCostPerDay,
        projectedMonthlyUsd: avgCostPerDay * 30,
        projectedYearlyUsd: avgCostPerDay * 365,
    };
    // Efficiency
    const totalTokens = totalInput + totalOutput;
    const costPer1KTokens = totalTokens > 0 ? (totalCost / totalTokens) * 1000 : 0;
    const avgRequestCostUsd = windowHistory.length > 0 ? totalCost / windowHistory.length : 0;
    return {
        days,
        windowRecords: windowHistory.length,
        totalCostUsd: totalCost,
        totalInputTokens: totalInput,
        totalOutputTokens: totalOutput,
        savedVsOpusUsd,
        byModel,
        daily,
        projections,
        avgRequestCostUsd,
        costPer1KTokens,
        byCategory: {
            chatCostUsd: chatCost,
            mediaCostUsd: mediaCost,
            sandboxCostUsd: sandboxCost,
            sandboxRequests,
        },
    };
}
// ─── Format for Display ───────────────────────────────────────────────────
function sparkline(values) {
    if (values.length === 0)
        return '';
    const max = Math.max(...values);
    if (max === 0)
        return '▁'.repeat(values.length);
    const chars = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'];
    return values.map(v => chars[Math.min(7, Math.floor((v / max) * 8))]).join('');
}
export function formatInsights(report, days) {
    const sep = '─'.repeat(60);
    const lines = [];
    lines.push('');
    lines.push(sep);
    lines.push(`  RUNCODE INSIGHTS — last ${days} days`);
    lines.push(sep);
    if (report.windowRecords === 0) {
        lines.push('');
        lines.push('  No activity in this window.');
        lines.push('');
        lines.push(sep);
        lines.push('');
        return lines.join('\n');
    }
    // Summary
    lines.push('');
    lines.push(`  Requests:     ${report.windowRecords}`);
    lines.push(`  Total cost:   ${formatUsd(report.totalCostUsd)}`);
    lines.push(`  Input tokens: ${formatTokens(report.totalInputTokens)}`);
    lines.push(`  Output tokens: ${formatTokens(report.totalOutputTokens)}`);
    lines.push(`  Avg/request:  ${formatUsd(report.avgRequestCostUsd)}  (${formatUsd(report.costPer1KTokens)}/1K tokens)`);
    if (report.savedVsOpusUsd > 0) {
        lines.push(`  Saved vs Opus: ${formatUsd(report.savedVsOpusUsd)} by using cheaper models`);
    }
    // Projections
    lines.push('');
    lines.push('  Projection:');
    lines.push(`    Per day:  ${formatUsd(report.projections.avgCostPerDay)}`);
    lines.push(`    Per month: ${formatUsd(report.projections.projectedMonthlyUsd)}`);
    lines.push(`    Per year: ${formatUsd(report.projections.projectedYearlyUsd)}`);
    // Per-model breakdown
    if (report.byModel.length > 0) {
        lines.push('');
        lines.push('  By model:');
        for (const m of report.byModel.slice(0, 10)) {
            const name = shortModelName(m.model).padEnd(30);
            const cost = formatUsd(m.costUsd).padStart(8);
            const pct = `${m.percentOfTotal.toFixed(0)}%`.padStart(4);
            const reqs = `${m.requests}req`.padStart(7);
            lines.push(`    ${name}  ${cost}  ${pct}  ${reqs}`);
        }
    }
    // Daily activity sparkline
    if (report.daily.length > 0) {
        const costs = report.daily.map(d => d.costUsd);
        const requests = report.daily.map(d => d.requests);
        lines.push('');
        lines.push('  Daily activity:');
        lines.push(`    Requests: ${sparkline(requests)}  ${report.daily[0].date} → ${report.daily[report.daily.length - 1].date}`);
        lines.push(`    Cost:     ${sparkline(costs)}`);
    }
    lines.push('');
    lines.push(sep);
    lines.push('');
    return lines.join('\n');
}
// Silence unused import warning
void MODEL_PRICING;
