'use strict';

/**
 * /api/ledger — the truth surface (Sessions 55 + 58).
 *
 *   GET /accuracy — grade-tier buckets (Session 55, snapshot-log based).
 *   GET /mine     — the caller's own ledger_entries, newest first (Phase 1).
 *   GET /model    — the PUBLIC model record (user_id NULL rows) + the 30d
 *                   aggregate {hit_pct, beat_close_pct, pending}. Percentages
 *                   are null below MIN_AGG_SAMPLE (20) — the UI renders
 *                   "RECORD BUILDING" instead. Never a % on a small n.
 */

const express = require('express');
const { createRateLimit } = require('../middleware/rateLimit');
const { requireAuth } = require('../middleware/auth');
const outcomeService = require('../services/outcomeService');
const ledgerService = require('../services/ledgerService');
const { nameKey } = require('../utils/playerName');

const router = express.Router();
router.use(createRateLimit({ windowMs: 60_000, max: 60 }));

const VALID_SPORTS = new Set(['nba', 'mlb', 'wnba', 'soccer']);
const VALID_TIERS = new Set(['A', 'B', 'C', 'D', 'F']);
const ROW_COLUMNS = 'id, player_key, player_name, sport, stat, line, side, locked_odds, book, grade, edge, confidence, model_value, graded_at, game_id, game_date, closing_line, closing_odds, clv, clv_result, outcome, actual_value, settled_at, revised_from_grade';

function sbOrNull() {
  try {
    if (!ledgerService.__internals.isConfigured()) return null;
    return require('../utils/supabase').getSupabaseServiceClient();
  } catch { return null; }
}

function applyFilters(query, req) {
  const sport = String(req.query.sport || '').toLowerCase();
  const tier = String(req.query.tier || req.query.grade || '').toUpperCase();
  if (VALID_SPORTS.has(sport)) query = query.eq('sport', sport);
  if (VALID_TIERS.has(tier)) query = query.ilike('grade', `${tier}%`);
  return query;
}

router.get('/accuracy', async (req, res) => {
  try {
    const acc = await outcomeService.getAccuracy();
    const buckets = outcomeService.accuracyBuckets(acc.overall);
    res.set('Cache-Control', 'public, max-age=300');
    return res.json({ buckets, overall: acc.overall && acc.overall.overall, updated_at: acc.updated_at });
  } catch (err) {
    console.error('[ledger/accuracy]', err.message);
    return res.status(200).json({ buckets: [] });
  }
});

// The caller's own reads. Service-role read scoped to req.user.id — clients
// never query the table directly (RLS blocks writes; reads go through here).
router.get('/mine', requireAuth, async (req, res) => {
  const sb = sbOrNull();
  if (!sb) return res.json({ entries: [] });
  try {
    const limit = Math.min(200, Math.max(1, Number(req.query.limit) || 100));
    let q = sb.from('ledger_entries')
      .select(ROW_COLUMNS)
      .eq('user_id', req.user.id);
    q = applyFilters(q, req);
    const { data, error } = await q
      .order('graded_at', { ascending: false })
      .limit(limit);
    if (error) throw new Error(error.message);
    return res.json({ entries: data || [] });
  } catch (err) {
    console.error('[ledger/mine]', err.message);
    return res.status(200).json({ entries: [] });
  }
});

// The public model record: every pipeline pre-grade, settled or pending,
// misses included. This is the product's proof surface.
router.get('/model', async (req, res) => {
  const sb = sbOrNull();
  try {
    const aggregate = await ledgerService.getModelAggregate({
      sport: VALID_SPORTS.has(String(req.query.sport || '').toLowerCase())
        ? String(req.query.sport).toLowerCase() : undefined,
      // VYNDR-on-player (work-order 1.4/5.2): per-player public record.
      playerKey: req.query.player ? nameKey(String(req.query.player).slice(0, 60)) : undefined,
      // VYNDR-on-team (5.2, migration 020): exact statsapi team name.
      team: req.query.team ? String(req.query.team).slice(0, 60) : undefined,
    });
    let entries = [];
    if (sb) {
      const limit = Math.min(200, Math.max(1, Number(req.query.limit) || 60));
      let q = sb.from('ledger_entries')
        .select(ROW_COLUMNS)
        .is('user_id', null);
      q = applyFilters(q, req);
      // Session 60 (night2/E) — PRIOR READS: a player's own public history.
      if (req.query.player) q = q.eq('player_key', nameKey(String(req.query.player).slice(0, 60)));
      // Session 64 (A1-S5) — the Yesterday results surface: rows for one game date.
      if (req.query.date && /^\d{4}-\d{2}-\d{2}$/.test(String(req.query.date))) {
        q = q.eq('game_date', String(req.query.date));
      }
      const { data, error } = await q
        .order('graded_at', { ascending: false })
        .limit(limit);
      if (error) throw new Error(error.message);
      entries = data || [];
    }
    res.set('Cache-Control', 'public, max-age=60');
    return res.json({ entries, aggregate, min_sample: ledgerService.MIN_AGG_SAMPLE });
  } catch (err) {
    console.error('[ledger/model]', err.message);
    return res.status(200).json({ entries: [], aggregate: null, min_sample: ledgerService.MIN_AGG_SAMPLE });
  }
});

module.exports = router;
