/**
 * Per-grade-tier accuracy tracking.
 *
 * Every resolution increments counters for (sport, grade, period).
 * The "all_time" period is the canonical record; "last_30d" and
 * "last_7d" are derived views recomputed by a periodic refresh job
 * (n8n). We update all three counters on every resolve so callers can
 * read instant values without rolling a window themselves.
 *
 * BASELINE LOCK:
 *   After a (sport, grade, 'all_time') accumulates 100 decisive
 *   resolutions (hits + misses, not push/void), the hit rate at that
 *   moment is locked as `baseline_hit_rate` and `baseline_locked`
 *   flips to true. Future accuracy compares to the baseline to detect
 *   drift.
 *
 * EXPECTED HIT RATES (from spec):
 *   A+ ≥ 65%, A ≥ 60%, A- ≥ 58%, B+ ≥ 55%, B ≥ 53%, B- ≥ 51%
 *   C+  ≈ 50%, C ≈ 48%, C- ≈ 45%, D ≈ 40%, F ≈ 35%
 */

const { getSupabaseServiceClient } = require('../../utils/supabase');

const BASELINE_LOCK_AT = 100;
const PERIODS = ['all_time', 'last_30d', 'last_7d'];

const EXPECTED_HIT_RATES = Object.freeze({
  'A+': 0.65, 'A': 0.60, 'A-': 0.58,
  'B+': 0.55, 'B': 0.53, 'B-': 0.51,
  'C+': 0.50, 'C': 0.48, 'C-': 0.45,
  'D':  0.40, 'F':  0.35,
});

function computeHitRate(hit, miss) {
  const denom = hit + miss;
  return denom > 0 ? hit / denom : null;
}

async function fetchRow(supabase, sport, grade, period) {
  const { data, error } = await supabase
    .from('accuracy_tracking')
    .select('*')
    .eq('sport', sport)
    .eq('grade', grade)
    .eq('period', period)
    .maybeSingle();
  if (error) {
    console.warn('[accuracy] fetch failed:', error.message);
    return null;
  }
  return data;
}

async function upsertRow(supabase, row) {
  const { error } = await supabase
    .from('accuracy_tracking')
    .upsert(row, { onConflict: 'sport,grade,period' });
  if (error) console.warn('[accuracy] upsert failed:', error.message);
}

async function recordResolution(sport, grade, result) {
  if (!sport || !grade || !result) return;
  const supabase = getSupabaseServiceClient();
  for (const period of PERIODS) {
    const existing = await fetchRow(supabase, sport, grade, period) || {
      sport, grade, period,
      total_graded: 0, total_hit: 0, total_miss: 0, total_push: 0, total_void: 0,
      hit_rate: null, baseline_hit_rate: null, baseline_locked: false,
    };
    existing.total_graded += 1;
    if (result === 'hit') existing.total_hit += 1;
    else if (result === 'miss') existing.total_miss += 1;
    else if (result === 'push') existing.total_push += 1;
    else if (result === 'void') existing.total_void += 1;
    existing.hit_rate = computeHitRate(existing.total_hit, existing.total_miss);

    if (
      period === 'all_time'
      && !existing.baseline_locked
      && (existing.total_hit + existing.total_miss) >= BASELINE_LOCK_AT
    ) {
      existing.baseline_hit_rate = existing.hit_rate;
      existing.baseline_locked = true;
    }
    existing.last_updated = new Date().toISOString();
    await upsertRow(supabase, existing);
  }
}

async function getAccuracy(sport, grade, period = 'all_time') {
  const supabase = getSupabaseServiceClient();
  const row = await fetchRow(supabase, sport, grade, period);
  if (!row) {
    return {
      sport, grade, period,
      hit_rate: null,
      baseline: null,
      expected: EXPECTED_HIT_RATES[grade] ?? null,
      total: 0,
      delta: null,
      locked: false,
    };
  }
  const total = row.total_hit + row.total_miss;
  const delta = row.baseline_hit_rate != null && row.hit_rate != null
    ? row.hit_rate - row.baseline_hit_rate
    : null;
  return {
    sport, grade, period,
    hit_rate: row.hit_rate,
    baseline: row.baseline_hit_rate,
    expected: EXPECTED_HIT_RATES[grade] ?? null,
    total,
    delta,
    locked: !!row.baseline_locked,
  };
}

async function getAllAccuracy(sport, period = 'all_time') {
  const grades = Object.keys(EXPECTED_HIT_RATES);
  const out = [];
  for (const grade of grades) out.push(await getAccuracy(sport, grade, period));
  return out;
}

async function isBaselineLocked(sport, grade) {
  const supabase = getSupabaseServiceClient();
  const row = await fetchRow(supabase, sport, grade, 'all_time');
  return !!row?.baseline_locked;
}

async function getAccuracyDashboard() {
  const supabase = getSupabaseServiceClient();
  const { data, error } = await supabase
    .from('accuracy_tracking')
    .select('*')
    .eq('period', 'all_time');
  if (error) {
    console.warn('[accuracy] dashboard query failed:', error.message);
    return [];
  }
  return data || [];
}

module.exports = {
  recordResolution,
  getAccuracy,
  getAllAccuracy,
  isBaselineLocked,
  getAccuracyDashboard,
  EXPECTED_HIT_RATES,
  BASELINE_LOCK_AT,
  __internals: { computeHitRate, PERIODS },
};
