'use strict';

/**
 * Provider registry (Session 20).
 *
 * Every external data provider VYNDR talks to is enumerated here.
 * Each entry declares:
 *   - envKey       — the environment variable holding the API key
 *                    (presence = the provider is configured)
 *   - quotaType    — 'monthly' | 'daily' | 'per_minute'
 *   - quotaLimit   — calls allowed per quotaType period
 *   - resetDay     — for monthly quotas, day-of-month the counter
 *                    resets (1 = first of the month). null otherwise.
 *   - sports       — which sport keys this provider covers
 *   - capabilities — what kinds of data it can return
 *   - priority     — 1 = primary for its capability set; higher
 *                    numbers are fallbacks
 *
 * The quotaTracker keys off provider IDs from this map. Wiring a
 * new provider = adding it here + having its adapter route through
 * providerGateway.fetch(providerId, callback, opts).
 *
 * IMPORTANT: keep quotaLimit conservative. Over-counting throttles
 * the platform under-load; under-counting blows the budget. If a
 * provider's actual limit changes (e.g. plan upgrade), update this
 * number — the tracker re-reads it each call.
 */

const PROVIDERS = {
  // === ODDS / LINES ===
  // Session 30 — PropLine is now PRIMARY for player props. 3 free keys
  // rotate for 3,000 req/day combined (vs odds-api's 500/MONTH), and its
  // response shape is The-Odds-API-compatible. The proplineAdapter handles
  // which physical key to use; the gateway counts total propline calls
  // against the 3,000/day cap here. odds-api drops to priority 2 (backup
  // we conserve). Configured when at least key 1 is present.
  'propline': {
    name: 'PropLine',
    envKey: 'PROPLINE_API_KEY_1',
    quotaType: 'daily',
    quotaLimit: 3000,
    resetDay: null,
    sports: ['nba', 'wnba', 'mlb', 'nfl', 'nhl'],
    capabilities: ['odds', 'props', 'lines', 'spreads'],
    priority: 1,
  },
  'odds-api': {
    name: 'The Odds API',
    envKey: 'ODDS_API_KEY',
    quotaType: 'monthly',
    quotaLimit: 500,
    resetDay: 1,
    sports: ['nba', 'wnba', 'mlb', 'soccer_wc', 'nfl', 'nhl'],
    capabilities: ['odds', 'props', 'lines', 'spreads'],
    priority: 2,
  },
  // Session 21 — correction. ODDSPAPI is NOT a live-props fallback
  // for the-odds-api. It serves Pinnacle CLOSING lines, captured at
  // tip-off into the `closing_lines` table for CLV tracking. The
  // `oddsPapiAdapter` calls /sports/{sportKey}/events/{gameId}/odds
  // with `bookmaker=pinnacle, market=player_props` ONCE per game.
  // Base URL: https://api.oddspapi.io/v1. Auth: X-Api-Key header.
  'oddspapi': {
    name: 'ODDSPAPI (Pinnacle close)',
    envKey: 'ODDSPAPI_KEY',
    quotaType: 'monthly',
    quotaLimit: 1000,
    resetDay: 1,
    sports: ['nba', 'wnba', 'mlb', 'nfl', 'nhl', 'ncaab', 'ncaafb'],
    capabilities: ['closing_lines'],
    priority: 1,
  },
  // Session 21 — correction. ParlayAPI is a historical-archive
  // provider, NOT a live-odds source. 1,000 credits/month free tier
  // ("drop-in for the-odds-api, up to 6x cheaper" — but used for
  // history, not real-time). Two endpoints in use:
  //   /historical/player_props  → hit rate enrichment
  //   /historical/closing_lines → CLV reference
  // Base URL: https://api.parlayapi.io/v1. Auth: X-Api-Key header.
  // Session 23 — DEAD. Chrome Claude confirmed on 2026-06-12 that
  // `api.parlayapi.io` no longer resolves (domain unreachable). We keep
  // the entry so the adapter code + its (network-mocked) tests still
  // resolve a config, but `status: 'dead'` removes it from every
  // fallback chain and the configured-providers list, so the gateway
  // never routes a live call to a host that doesn't exist.
  'parlayapi': {
    name: 'ParlayAPI (historical)',
    envKey: 'PARLAYAPI_KEY',
    status: 'dead',
    quotaType: 'monthly',
    quotaLimit: 1000,
    resetDay: 1,
    sports: ['nba', 'wnba', 'mlb', 'nfl', 'nhl', 'ncaab', 'ncaafb'],
    capabilities: ['historical_props', 'historical_lines'],
    priority: 1,
  },

  // === STATS / BOX SCORES ===
  'tank01': {
    name: 'Tank01 (RapidAPI)',
    envKey: 'RAPID_API_KEY',
    quotaType: 'monthly',
    quotaLimit: 1000,
    resetDay: 1,
    sports: ['nba', 'mlb'],
    capabilities: ['box_scores', 'schedules', 'player_stats', 'bvp'],
    priority: 1,
  },
  // Session 30 — official MLB data. FREE, no auth, unlimited. The
  // mlbStatsAdapter does NOT route through the gateway (no quota to
  // track); this entry is informational + surfaces it on the admin
  // dashboard. `noAuth` marks it always-configured (no env key gate).
  'mlb-stats': {
    name: 'MLB Stats API',
    envKey: null,
    noAuth: true,
    quotaType: 'unlimited',
    quotaLimit: null,
    resetDay: null,
    sports: ['mlb'],
    capabilities: ['game_logs', 'season_averages', 'splits', 'probable_pitchers', 'bvp'],
    priority: 1,
  },

  // === SOCCER ===
  'api-football': {
    name: 'API-Football',
    envKey: 'API_FOOTBALL_KEY',
    quotaType: 'daily',
    quotaLimit: 100,
    resetDay: null,
    sports: ['soccer_wc', 'soccer'],
    capabilities: ['lineups', 'player_stats', 'match_events', 'live_scores'],
    priority: 1,
  },
  'football-data': {
    name: 'Football-Data.org',
    envKey: 'FOOTBALL_DATA_API_KEY',
    quotaType: 'per_minute',
    quotaLimit: 10,
    resetDay: null,
    sports: ['soccer_wc', 'soccer'],
    capabilities: ['standings', 'fixtures', 'scorers'],
    priority: 2,
  },
};

/**
 * Threshold constants — shared by quotaTracker and providerGateway
 * so the WARN/BLOCK lines stay in lockstep.
 */
const THRESHOLDS = Object.freeze({
  WARN_PCT: 0.80,
  BLOCK_PCT: 0.95,
});

function getProvider(providerId) {
  return PROVIDERS[providerId] || null;
}

function listProviderIds() {
  return Object.keys(PROVIDERS);
}

/**
 * Subset of providers whose envKey is set. Logged at startup; used
 * by the admin dashboard to render only providers the operator has
 * actually wired up.
 */
// A provider counts as configured when its key is present OR it needs no
// auth at all (e.g. MLB Stats API). Dead providers are always excluded.
function isProviderConfigured(cfg) {
  if (!cfg || cfg.status === 'dead') return false;
  return cfg.noAuth === true || !!(cfg.envKey && process.env[cfg.envKey]);
}

function getConfiguredProviders() {
  return Object.entries(PROVIDERS)
    .filter(([, cfg]) => isProviderConfigured(cfg))
    .map(([id, cfg]) => ({ id, ...cfg }));
}

/** True when a provider is retired (e.g. its host no longer resolves). */
function isDeadProvider(providerId) {
  return PROVIDERS[providerId]?.status === 'dead';
}

/**
 * Fallback chain for a capability + sport, in priority order,
 * excluding `excludeId`. Used by the gateway to walk down to the
 * next provider when the primary is exhausted.
 */
function getFallbackChain(capability, sport, excludeId) {
  return Object.entries(PROVIDERS)
    .filter(([id, cfg]) =>
      id !== excludeId &&
      cfg.capabilities.includes(capability) &&
      (!sport || cfg.sports.includes(sport)) &&
      isProviderConfigured(cfg),  // excludes dead + unconfigured, includes noAuth
    )
    .sort((a, b) => a[1].priority - b[1].priority)
    .map(([id]) => id);
}

module.exports = {
  PROVIDERS,
  THRESHOLDS,
  getProvider,
  listProviderIds,
  getConfiguredProviders,
  getFallbackChain,
  isDeadProvider,
  isProviderConfigured,
};
