/**
 * Metrics Command - Show provider metrics
 *
 * Displays LLM provider usage metrics including token counts,
 * estimated costs, session counts, and error rates.
 */
import { success, failure, ExitCode } from '../types.js';
import { createAPI } from '../db.js';
// ============================================================================
// Helpers
// ============================================================================
/**
 * Parse a time range string (e.g., '7d', '14d', '30d') to number of days.
 */
function parseTimeRange(value) {
    if (!value)
        return 7;
    const match = value.match(/^(\d+)d$/);
    if (match) {
        const days = parseInt(match[1], 10);
        if (days > 0 && days <= 365)
            return days;
    }
    return 7;
}
/**
 * Rough cost estimate based on token counts.
 * Uses approximate Claude pricing: $3/MTok input, $15/MTok output.
 */
function estimateCost(inputTokens, outputTokens) {
    const inputCost = (inputTokens / 1_000_000) * 3;
    const outputCost = (outputTokens / 1_000_000) * 15;
    return inputCost + outputCost;
}
/**
 * Format a number with thousands separators
 */
function formatNumber(n) {
    return n.toLocaleString('en-US');
}
/**
 * Format milliseconds as human-readable duration
 */
function formatDuration(ms) {
    if (ms < 1000)
        return `${ms}ms`;
    const seconds = Math.round(ms / 1000);
    if (seconds < 60)
        return `${seconds}s`;
    const minutes = Math.floor(seconds / 60);
    const remainingSeconds = seconds % 60;
    if (minutes < 60)
        return `${minutes}m ${remainingSeconds}s`;
    const hours = Math.floor(minutes / 60);
    const remainingMinutes = minutes % 60;
    return `${hours}h ${remainingMinutes}m`;
}
/**
 * Format cost as a dollar amount
 */
function formatCost(cost) {
    if (cost < 0.01)
        return '$0.00';
    return `$${cost.toFixed(2)}`;
}
/**
 * Query aggregated metrics directly from the database
 */
function queryMetrics(backend, days, groupBy, providerFilter) {
    const cutoff = new Date();
    cutoff.setDate(cutoff.getDate() - days);
    const cutoffStr = cutoff.toISOString();
    const groupExpr = groupBy === 'provider' ? 'provider' : "COALESCE(model, 'unknown')";
    const params = [cutoffStr];
    let whereClause = 'WHERE timestamp >= ?';
    if (providerFilter) {
        whereClause += ' AND provider = ?';
        params.push(providerFilter);
    }
    return backend.query(`SELECT
       ${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,
       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
     ${whereClause}
     GROUP BY group_key
     ORDER BY total_input_tokens + total_output_tokens DESC`, params);
}
// ============================================================================
// Handler
// ============================================================================
async function metricsHandler(_args, options) {
    const { backend, error } = createAPI(options);
    if (error) {
        return failure(error, ExitCode.GENERAL_ERROR);
    }
    try {
        const days = parseTimeRange(options.range);
        const providerFilter = options.provider;
        const groupBy = options['group-by'] === 'model' ? 'model' : 'provider';
        const rows = queryMetrics(backend, days, groupBy, providerFilter);
        const metrics = 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),
            estimatedCost: estimateCost(Number(row.total_input_tokens), Number(row.total_output_tokens)),
        }));
        const totals = {
            totalInputTokens: metrics.reduce((sum, m) => sum + m.totalInputTokens, 0),
            totalOutputTokens: metrics.reduce((sum, m) => sum + m.totalOutputTokens, 0),
            totalTokens: metrics.reduce((sum, m) => sum + m.totalTokens, 0),
            sessionCount: metrics.reduce((sum, m) => sum + m.sessionCount, 0),
            estimatedCost: metrics.reduce((sum, m) => sum + m.estimatedCost, 0),
        };
        const summary = {
            timeRange: { days, label: `${days}d` },
            groupBy,
            metrics,
            totals,
        };
        // Build human-readable output
        const lines = [];
        const groupLabel = groupBy === 'provider' ? 'Provider' : 'Model';
        lines.push(`Provider Metrics (last ${days} days)`);
        if (providerFilter) {
            lines.push(`Filtered by provider: ${providerFilter}`);
        }
        lines.push('');
        if (metrics.length === 0) {
            lines.push('No metrics recorded for the selected time range.');
            return success(summary, lines.join('\n'));
        }
        // Summary totals
        lines.push('Summary:');
        lines.push(`  Total tokens:     ${formatNumber(totals.totalTokens)}`);
        lines.push(`  Input tokens:     ${formatNumber(totals.totalInputTokens)}`);
        lines.push(`  Output tokens:    ${formatNumber(totals.totalOutputTokens)}`);
        lines.push(`  Sessions:         ${formatNumber(totals.sessionCount)}`);
        lines.push(`  Estimated cost:   ${formatCost(totals.estimatedCost)}`);
        lines.push('');
        // Per-group breakdown
        lines.push(`By ${groupLabel}:`);
        lines.push('');
        for (const m of metrics) {
            lines.push(`  ${m.group}`);
            lines.push(`    Tokens:      ${formatNumber(m.totalTokens)} (in: ${formatNumber(m.totalInputTokens)}, out: ${formatNumber(m.totalOutputTokens)})`);
            lines.push(`    Sessions:    ${formatNumber(m.sessionCount)}`);
            lines.push(`    Avg duration: ${formatDuration(m.avgDurationMs)}`);
            lines.push(`    Error rate:  ${(m.errorRate * 100).toFixed(1)}% (${m.failedCount} failed, ${m.rateLimitedCount} rate limited)`);
            lines.push(`    Est. cost:   ${formatCost(m.estimatedCost)}`);
            lines.push('');
        }
        return success(summary, lines.join('\n'));
    }
    catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        return failure(`Failed to get metrics: ${message}`, ExitCode.GENERAL_ERROR);
    }
}
// ============================================================================
// Command Options
// ============================================================================
const metricsOptions = [
    {
        name: 'range',
        short: 'r',
        description: 'Time range (e.g., 7d, 14d, 30d)',
        hasValue: true,
    },
    {
        name: 'provider',
        short: 'p',
        description: 'Filter by provider name',
        hasValue: true,
    },
    {
        name: 'group-by',
        short: 'g',
        description: 'Group by: provider (default) or model',
        hasValue: true,
    },
];
// ============================================================================
// Command Definition
// ============================================================================
export const metricsCommand = {
    name: 'metrics',
    description: 'Show provider metrics and usage statistics',
    usage: 'sf metrics [options]',
    help: `Show LLM provider usage metrics including token counts, estimated costs,
session counts, average duration, and error rates.

Options:
  --range, -r    Time range (e.g., 7d, 14d, 30d). Default: 7d
  --provider, -p Filter by provider name (e.g., claude-code)
  --group-by, -g Group by: provider (default) or model

Examples:
  sf metrics                  Show metrics for last 7 days
  sf metrics --range 30d      Show metrics for last 30 days
  sf metrics --provider claude-code  Filter by provider
  sf metrics --group-by model        Group by model
  sf metrics --json           Output as JSON`,
    handler: metricsHandler,
    options: metricsOptions,
};
//# sourceMappingURL=metrics.js.map