#!/usr/bin/env node
/**
 * ParlayAPI historical pull.
 *
 * BULK operation — runs for hours, not seconds. Free tier is 1,000 credits
 * per month, so we walk one (sport, date) at a time with a checkpoint in
 * Redis so an interrupted run can resume right where it stopped.
 *
 * Usage:
 *   node scripts/pull-parlayapi-history.js nba 2025      # one sport / season
 *   node scripts/pull-parlayapi-history.js all            # all active sports
 *   node scripts/pull-parlayapi-history.js --resume       # continue from checkpoint
 *   node scripts/pull-parlayapi-history.js --dry-run      # don't insert
 *   node scripts/pull-parlayapi-history.js --yes          # skip confirmation
 *
 * Pace: 2 requests / minute. Set PARLAYAPI_PULL_RATE in env to override.
 */

if (require.main !== module) {
  throw new Error('Run directly: node scripts/pull-parlayapi-history.js');
}

const path = require('path');
const readline = require('readline');
require('dotenv').config({ path: path.join(__dirname, '..', '.env') });

const { getSupabaseServiceClient } = require('../src/utils/supabase');
const { getRedisClient } = require('../src/utils/redis');
const parlayApi = require('../src/services/adapters/parlayApiAdapter');
const { getActiveSports } = require('../src/config/sports');

const args = process.argv.slice(2);
const dryRun = args.includes('--dry-run');
const resume = args.includes('--resume');
const skipConfirm = args.includes('--yes');
const positional = args.filter((a) => !a.startsWith('--'));
const sportArg = positional[0];
const seasonArg = positional[1];

const RATE_MS = Number(process.env.PARLAYAPI_PULL_RATE_MS) || 30_000;  // 2/min by default
const SEASON_DEFAULT = new Date().getFullYear();

function sleep(ms) { return new Promise((r) => setTimeout(r, ms)); }

async function confirm(question) {
  if (skipConfirm) return true;
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
  const answer = await new Promise((r) => rl.question(question, r));
  rl.close();
  return /^y(es)?$/i.test(answer.trim());
}

function* dateRange(season) {
  // Walk a season's worth of days. ParlayAPI's date arg is YYYY-MM-DD.
  // For each season we cover Aug 1 → Jul 31 of the following calendar
  // year — that umbrella catches every sport's annual span.
  const start = new Date(Date.UTC(season, 7, 1));
  const end = new Date(Date.UTC(season + 1, 6, 31));
  const cursor = new Date(start);
  while (cursor <= end) {
    yield cursor.toISOString().slice(0, 10);
    cursor.setUTCDate(cursor.getUTCDate() + 1);
  }
}

async function checkpointKey(sport, season) {
  return `parlayapi:checkpoint:${sport}:${season}`;
}

async function readCheckpoint(sport, season) {
  const redis = getRedisClient();
  return redis.get(await checkpointKey(sport, season));
}

async function writeCheckpoint(sport, season, date) {
  const redis = getRedisClient();
  await redis.set(await checkpointKey(sport, season), date, 'EX', 30 * 24 * 60 * 60);
}

async function processSportSeason(sport, season) {
  console.log(`[parlayapi-pull] ${sport} ${season} starting (rate=${RATE_MS}ms)`);
  let totalInserted = 0;
  let lastSeen = null;
  if (resume) {
    lastSeen = await readCheckpoint(sport, season);
    if (lastSeen) console.log(`[parlayapi-pull] resuming after ${lastSeen}`);
  }

  for (const date of dateRange(season)) {
    if (lastSeen && date <= lastSeen) continue;
    let lines;
    try {
      lines = await parlayApi.getClosingLines(sport, date);
    } catch (err) {
      console.warn(`[parlayapi-pull] ${date} failed: ${err.message}`);
      await sleep(RATE_MS);
      continue;
    }
    if (lines.length && !dryRun) {
      const supabase = getSupabaseServiceClient();
      const rows = lines.map((l) => ({
        sport,
        game_date: date,
        player_name: l.player ?? l.player_name ?? 'unknown',
        stat_type: l.stat_type ?? l.market ?? 'unknown',
        line: Number(l.line ?? l.point ?? 0),
        closing_line: Number(l.closing_line ?? l.close ?? null) || null,
        result: l.result ?? l.outcome ?? null,
        source: 'parlayapi',
      }));
      const { error } = await supabase.from('historical_props').insert(rows);
      if (error) {
        console.warn(`[parlayapi-pull] insert failed for ${date}: ${error.message}`);
      } else {
        totalInserted += rows.length;
      }
    }
    await writeCheckpoint(sport, season, date);
    if (dryRun) {
      console.log(`[parlayapi-pull] dry-run ${date} → ${lines.length} lines`);
    }
    await sleep(RATE_MS);
  }
  console.log(`[parlayapi-pull] ${sport} ${season} done — inserted ${totalInserted} rows`);
  return totalInserted;
}

async function main() {
  if (!parlayApi.configured()) {
    console.error('PARLAYAPI_KEY is not set');
    process.exit(2);
  }
  const sportList = sportArg && sportArg !== 'all'
    ? [sportArg]
    : getActiveSports().map((s) => s.key);
  const season = Number(seasonArg) || SEASON_DEFAULT;

  if (!dryRun) {
    const ok = await confirm(
      `This will insert ParlayAPI history for ${sportList.join(', ')} ${season} into ${process.env.SUPABASE_URL || '(unknown)'}. Continue? (y/n) `
    );
    if (!ok) { console.log('aborted'); process.exit(0); }
  }

  for (const sport of sportList) {
    try { await processSportSeason(sport, season); }
    catch (err) { console.error(`[parlayapi-pull] ${sport} fatal: ${err.message}`); }
  }
}

main().catch((err) => {
  console.error('[parlayapi-pull] fatal:', err.message);
  process.exit(1);
});
