/**
 * Metrics Service
 *
 * Records and aggregates provider metrics for LLM usage tracking.
 * Stores data in the provider_metrics SQLite table and provides
 * aggregation queries for dashboards and CLI reporting.
 */
import { createLogger } from '../utils/logger.js';
const logger = createLogger('metrics-service');
// ============================================================================
// Helpers
// ============================================================================
function generateMetricId() {
    const timestamp = Date.now().toString(36);
    const random = Math.random().toString(36).slice(2, 8);
    return `pm-${timestamp}-${random}`;
}
function getTimeCutoff(timeRange) {
    const cutoff = new Date();
    cutoff.setDate(cutoff.getDate() - timeRange.days);
    return cutoff.toISOString();
}
/**
 * Determine the appropriate time bucket size based on the time range.
 * Uses SQLite date functions for grouping.
 */
function getTimeBucketExpression(timeRange) {
    if (timeRange.days <= 7) {
        // Daily buckets for 7 days or less
        return "date(timestamp)";
    }
    else if (timeRange.days <= 30) {
        // Daily buckets for up to 30 days
        return "date(timestamp)";
    }
    else {
        // Weekly buckets for longer ranges
        return "date(timestamp, 'weekday 0', '-6 days')";
    }
}
// ============================================================================
// Implementation
// ============================================================================
export function createMetricsService(storage) {
    return {
        record(input) {
            const id = generateMetricId();
            const timestamp = new Date().toISOString();
            try {
                storage.run(`INSERT INTO provider_metrics (id, timestamp, provider, model, session_id, task_id, input_tokens, output_tokens, duration_ms, outcome)
           VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
                    id,
                    timestamp,
                    input.provider,
                    input.model ?? null,
                    input.sessionId,
                    input.taskId ?? null,
                    input.inputTokens,
                    input.outputTokens,
                    input.durationMs,
                    input.outcome,
                ]);
                logger.debug(`Metric recorded: ${input.provider}/${input.model ?? 'unknown'} - ${input.outcome} (${input.inputTokens + input.outputTokens} tokens)`);
            }
            catch (err) {
                logger.error('Failed to record metric:', err);
            }
        },
        aggregateByProvider(timeRange) {
            const cutoff = getTimeCutoff(timeRange);
            const rows = storage.query(`SELECT
           provider AS group_key,
           COALESCE(SUM(input_tokens), 0) AS total_input_tokens,
           COALESCE(SUM(output_tokens), 0) AS total_output_tokens,
           COUNT(*) AS session_count,
           COALESCE(AVG(duration_ms), 0) AS avg_duration_ms,
           COALESCE(SUM(CASE WHEN outcome = 'failed' THEN 1 ELSE 0 END), 0) AS failed_count,
           COALESCE(SUM(CASE WHEN outcome = 'rate_limited' THEN 1 ELSE 0 END), 0) AS rate_limited_count
         FROM provider_metrics
         WHERE timestamp >= ?
         GROUP BY provider
         ORDER BY total_input_tokens + total_output_tokens DESC`, [cutoff]);
            return rows.map(row => ({
                group: row.group_key,
                totalInputTokens: Number(row.total_input_tokens),
                totalOutputTokens: Number(row.total_output_tokens),
                totalTokens: Number(row.total_input_tokens) + Number(row.total_output_tokens),
                sessionCount: Number(row.session_count),
                avgDurationMs: Math.round(Number(row.avg_duration_ms)),
                errorRate: Number(row.session_count) > 0
                    ? Number(row.failed_count) / Number(row.session_count)
                    : 0,
                failedCount: Number(row.failed_count),
                rateLimitedCount: Number(row.rate_limited_count),
            }));
        },
        aggregateByModel(timeRange) {
            const cutoff = getTimeCutoff(timeRange);
            const rows = storage.query(`SELECT
           COALESCE(model, 'unknown') AS group_key,
           COALESCE(SUM(input_tokens), 0) AS total_input_tokens,
           COALESCE(SUM(output_tokens), 0) AS total_output_tokens,
           COUNT(*) AS session_count,
           COALESCE(AVG(duration_ms), 0) AS avg_duration_ms,
           COALESCE(SUM(CASE WHEN outcome = 'failed' THEN 1 ELSE 0 END), 0) AS failed_count,
           COALESCE(SUM(CASE WHEN outcome = 'rate_limited' THEN 1 ELSE 0 END), 0) AS rate_limited_count
         FROM provider_metrics
         WHERE timestamp >= ?
         GROUP BY COALESCE(model, 'unknown')
         ORDER BY total_input_tokens + total_output_tokens DESC`, [cutoff]);
            return rows.map(row => ({
                group: row.group_key,
                totalInputTokens: Number(row.total_input_tokens),
                totalOutputTokens: Number(row.total_output_tokens),
                totalTokens: Number(row.total_input_tokens) + Number(row.total_output_tokens),
                sessionCount: Number(row.session_count),
                avgDurationMs: Math.round(Number(row.avg_duration_ms)),
                errorRate: Number(row.session_count) > 0
                    ? Number(row.failed_count) / Number(row.session_count)
                    : 0,
                failedCount: Number(row.failed_count),
                rateLimitedCount: Number(row.rate_limited_count),
            }));
        },
        getTimeSeries(timeRange, groupBy) {
            const cutoff = getTimeCutoff(timeRange);
            const bucketExpr = getTimeBucketExpression(timeRange);
            const groupExpr = groupBy === 'provider' ? 'provider' : "COALESCE(model, 'unknown')";
            const rows = storage.query(`SELECT
           ${bucketExpr} AS bucket,
           ${groupExpr} AS group_key,
           COALESCE(SUM(input_tokens), 0) AS total_input_tokens,
           COALESCE(SUM(output_tokens), 0) AS total_output_tokens,
           COUNT(*) AS session_count,
           COALESCE(AVG(duration_ms), 0) AS avg_duration_ms
         FROM provider_metrics
         WHERE timestamp >= ?
         GROUP BY bucket, group_key
         ORDER BY bucket ASC, group_key ASC`, [cutoff]);
            return rows.map(row => ({
                bucket: row.bucket,
                group: row.group_key,
                totalInputTokens: Number(row.total_input_tokens),
                totalOutputTokens: Number(row.total_output_tokens),
                sessionCount: Number(row.session_count),
                avgDurationMs: Math.round(Number(row.avg_duration_ms)),
            }));
        },
    };
}
//# sourceMappingURL=metrics-service.js.map