'use strict';

/**
 * Score aggregator — rolls up shadow eval scores into model_task_scores.
 * Computes rolling window stats, trends, and win rates.
 */

/**
 * Detect trend from 7-day and 30-day averages.
 * @param {number|null} score7d
 * @param {number|null} score30d
 * @returns {'improving'|'stable'|'declining'}
 */
function detectTrend(score7d, score30d) {
  if (score7d == null || score30d == null) return 'stable';
  const diff = score7d - score30d;
  if (diff > 0.05) return 'improving';
  if (diff < -0.05) return 'declining';
  return 'stable';
}

/**
 * Aggregate scores for a specific model and task type.
 * Queries shadow_results directly for rolling window stats.
 *
 * @param {Object} brain - Brain module
 * @param {string} model - Shadow model name
 * @param {string} taskType - Task type
 * @param {number} [windowDays=30] - Rolling window in days
 * @returns {Object} Aggregated stats
 */
function aggregateScores(brain, model, taskType, windowDays = 30) {
  const db = brain.getDb();
  const cutoff30d = new Date(Date.now() - windowDays * 86400000).toISOString();
  const cutoff7d = new Date(Date.now() - 7 * 86400000).toISOString();

  // 30-day window stats
  const stats30d = db.prepare(`
    SELECT
      COUNT(*) AS total_evals,
      AVG(shadow_score) AS avg_score,
      SUM(CASE WHEN shadow_score >= 0.8 * COALESCE(primary_score, 1.0) THEN 1 ELSE 0 END) AS win_count,
      SUM(CASE WHEN shadow_score >= COALESCE(primary_score, 1.0) THEN 1 ELSE 0 END) AS strong_win_count,
      AVG(shadow_latency_ms) AS avg_latency_ms,
      MAX(evaluated_at) AS last_eval_at
    FROM shadow_results
    WHERE shadow_model = ? AND task_type = ?
      AND evaluated_at IS NOT NULL
      AND created_at >= ?
  `).get(model, taskType, cutoff30d);

  // 7-day window stats
  const stats7d = db.prepare(`
    SELECT AVG(shadow_score) AS avg_score
    FROM shadow_results
    WHERE shadow_model = ? AND task_type = ?
      AND evaluated_at IS NOT NULL
      AND created_at >= ?
  `).get(model, taskType, cutoff7d);

  const score7d = stats7d?.avg_score ?? null;
  const score30d = stats30d?.avg_score ?? null;
  const trend = detectTrend(score7d, score30d);

  return {
    model,
    taskType,
    provider: 'ollama', // Default; could be enhanced to detect from config
    totalEvals: stats30d?.total_evals || 0,
    avgScore: Math.round((stats30d?.avg_score || 0) * 1000) / 1000,
    winCount: stats30d?.win_count || 0,
    strongWinCount: stats30d?.strong_win_count || 0,
    avgLatencyMs: Math.round(stats30d?.avg_latency_ms || 0),
    score7d: score7d != null ? Math.round(score7d * 1000) / 1000 : null,
    score30d: score30d != null ? Math.round(score30d * 1000) / 1000 : null,
    trend,
    lastEvalAt: stats30d?.last_eval_at || null,
  };
}

/**
 * Get all distinct (model, task_type) pairs from shadow_results that have been evaluated.
 */
function getDistinctModelTaskPairs(brain) {
  return brain.getDb().prepare(`
    SELECT DISTINCT shadow_model AS model, task_type
    FROM shadow_results
    WHERE evaluated_at IS NOT NULL AND shadow_model IS NOT NULL
  `).all();
}

/**
 * Refresh all model_task_scores by re-aggregating from shadow_results.
 * @param {Object} brain - Brain module
 * @returns {{ updated: number, pairs: Array }}
 */
function updateAllModelTaskScores(brain) {
  const pairs = getDistinctModelTaskPairs(brain);
  const updated = [];

  for (const { model, task_type: taskType } of pairs) {
    const stats = aggregateScores(brain, model, taskType);
    brain.upsertModelTaskScore(model, taskType, stats);
    updated.push({ model, taskType, avgScore: stats.avgScore, totalEvals: stats.totalEvals, trend: stats.trend });
  }

  return { updated: updated.length, pairs: updated };
}

module.exports = {
  detectTrend,
  aggregateScores,
  getDistinctModelTaskPairs,
  updateAllModelTaskScores,
};
