/**
 * Team Logo Sync Worker
 *
 * Modes:
 *   --bootstrap-only  Scan existing /public/logos/ PNGs and create DB records
 *   --incremental     Only process teams NOT yet in rm_team_logos (for hourly runs)
 *   --force           Re-resolve even if already resolved (but not admin_override)
 *   (default daily)   7-day lookahead + retry all failed teams through full pipeline
 *
 * Usage: npx tsx src/workers/sync-team-logos.ts [--bootstrap-only] [--force] [--incremental] [--dry-run]
 */

import 'dotenv/config';
import fs from 'fs';
import path from 'path';
import crypto from 'crypto';
import pool from '../db';
import { upsertLogoRecord, getLogoRecord } from '../models/logo';
import { resolveTeamLogo, normalizeAbbr, getLogoLeague } from '../services/team-asset';

const LOGO_ROOT = path.resolve(__dirname, '../../../public/logos');
const bootstrapOnly = process.argv.includes('--bootstrap-only');
const force = process.argv.includes('--force');
const incremental = process.argv.includes('--incremental');
const dryRun = process.argv.includes('--dry-run');

function sha256File(filePath: string): string {
  const data = fs.readFileSync(filePath);
  return crypto.createHash('sha256').update(data).digest('hex');
}

/**
 * Bootstrap: scan all existing logo PNGs and create DB rows
 */
async function bootstrap(): Promise<number> {
  console.log('\n--- BOOTSTRAP: cataloging existing logos ---');
  let count = 0;

  const leagues = fs.readdirSync(LOGO_ROOT).filter(f =>
    fs.statSync(path.join(LOGO_ROOT, f)).isDirectory()
  );

  for (const league of leagues) {
    const dir = path.join(LOGO_ROOT, league);
    const files = fs.readdirSync(dir).filter(f => f.endsWith('.png'));

    for (const file of files) {
      const abbr = file.replace('.png', '');
      const fullPath = path.join(dir, file);
      const relativePath = `/logos/${league}/${file}`;
      const checksum = sha256File(fullPath);

      if (dryRun) {
        console.log(`  [DRY] ${league}/${abbr} — ${relativePath}`);
      } else {
        await upsertLogoRecord(league, abbr, {
          file_path: relativePath,
          file_exists: true,
          checksum_sha256: checksum,
          source: 'local_cache',
          resolution_status: 'resolved',
        });
      }
      count++;
    }

    console.log(`  ${league}: ${files.length} logos`);
  }

  return count;
}

/**
 * Sync: find teams from next 7 days of rm_events that are missing logos
 * In --incremental mode, only process teams not yet in rm_team_logos
 */
async function syncFromEvents(): Promise<{ resolved: number; fallback: number; failed: number; skipped: number }> {
  const modeLabel = incremental ? 'INCREMENTAL' : 'DAILY';
  console.log(`\n--- SYNC (${modeLabel}): resolving logos from upcoming events ---`);

  // 7-day lookahead instead of just today
  const { rows: events } = await pool.query(`
    SELECT DISTINCT league,
           home_team, home_short,
           away_team, away_short
    FROM rm_events
    WHERE starts_at BETWEEN NOW() AND NOW() + interval '7 days'
  `);

  if (events.length === 0) {
    console.log('  No events in next 7 days — nothing to sync.');
    return { resolved: 0, fallback: 0, failed: 0, skipped: 0 };
  }

  // Build unique team list
  const teams: Array<{ league: string; abbr: string; name: string }> = [];
  const seen = new Set<string>();

  for (const e of events) {
    const lg = e.league?.toLowerCase();
    if (!lg) continue;

    for (const side of ['home', 'away'] as const) {
      const abbr = side === 'home' ? e.home_short : e.away_short;
      const name = side === 'home' ? e.home_team : e.away_team;
      if (!abbr) continue;

      const normalizedAbbr = normalizeAbbr(abbr);
      const logoLeague = getLogoLeague(lg);
      const key = `${logoLeague}:${normalizedAbbr}`;
      if (seen.has(key)) continue;
      seen.add(key);

      teams.push({ league: lg, abbr, name });
    }
  }

  console.log(`  Found ${teams.length} unique teams across ${events.length} event rows`);

  let resolved = 0, fallback = 0, failed = 0, skipped = 0;

  for (const team of teams) {
    const normalizedAbbr = normalizeAbbr(team.abbr);
    const logoLeague = getLogoLeague(team.league);

    // In incremental mode, skip teams already in DB
    if (incremental) {
      const existing = await getLogoRecord(logoLeague, normalizedAbbr);
      if (existing) {
        skipped++;
        continue;
      }
    }

    if (dryRun) {
      console.log(`  [DRY] Would resolve: ${team.league}/${team.abbr} (${team.name})`);
      skipped++;
      continue;
    }

    const result = await resolveTeamLogo(team.league, team.abbr, team.name, force);

    if (result.status === 'resolved') {
      if (result.source !== 'local_cache') {
        console.log(`  [NEW] ${team.league}/${team.abbr}: ${result.message}`);
      }
      resolved++;
    } else if (result.status === 'fallback') {
      console.log(`  [MONO] ${team.league}/${team.abbr} (${team.name}): ${result.message}`);
      fallback++;
    } else if (result.status === 'failed') {
      console.log(`  [MISS] ${team.league}/${team.abbr} (${team.name}): ${result.message}`);
      failed++;
    } else {
      skipped++;
    }
  }

  return { resolved, fallback, failed, skipped };
}

/**
 * Retry all currently failed teams through the full pipeline
 * (TheSportsDB → ESPN → monogram). Only runs on daily (non-incremental) sync.
 */
async function retryFailed(): Promise<{ resolved: number; fallback: number; stillFailed: number }> {
  console.log('\n--- RETRY: re-attempting failed teams ---');

  const { rows: failedTeams } = await pool.query(`
    SELECT league, team_abbr, team_name
    FROM rm_team_logos
    WHERE resolution_status = 'failed'
      AND admin_override = FALSE
    ORDER BY league, team_abbr
  `);

  if (failedTeams.length === 0) {
    console.log('  No failed teams to retry.');
    return { resolved: 0, fallback: 0, stillFailed: 0 };
  }

  console.log(`  Found ${failedTeams.length} failed teams to retry`);

  let resolved = 0, fallback = 0, stillFailed = 0;

  for (const team of failedTeams) {
    if (dryRun) {
      console.log(`  [DRY] Would retry: ${team.league}/${team.team_abbr}`);
      continue;
    }

    const result = await resolveTeamLogo(
      team.league,
      team.team_abbr,
      team.team_name || team.team_abbr,
      true // force re-resolve
    );

    if (result.status === 'resolved') {
      console.log(`  [FIXED] ${team.league}/${team.team_abbr}: ${result.message}`);
      resolved++;
    } else if (result.status === 'fallback') {
      console.log(`  [MONO] ${team.league}/${team.team_abbr}: ${result.message}`);
      fallback++;
    } else {
      stillFailed++;
    }
  }

  return { resolved, fallback, stillFailed };
}

async function main() {
  const startTime = Date.now();
  console.log('='.repeat(60));
  console.log('RAINMAKER TEAM LOGO SYNC');
  console.log(`Date: ${new Date().toISOString()}`);
  const mode = bootstrapOnly ? 'BOOTSTRAP' : incremental ? 'INCREMENTAL' : 'DAILY';
  console.log(`Mode: ${mode}${force ? ' (force)' : ''}${dryRun ? ' (dry-run)' : ''}`);
  console.log('='.repeat(60));

  if (bootstrapOnly) {
    const count = await bootstrap();
    console.log(`\nBootstrap complete: ${count} logos cataloged.`);
  } else {
    // Always bootstrap first to ensure DB is in sync with disk
    const bootstrapCount = await bootstrap();
    console.log(`  Bootstrapped ${bootstrapCount} existing logos`);

    const result = await syncFromEvents();
    console.log('\n' + '-'.repeat(40));
    console.log('SYNC RESULTS');
    console.log(`  Resolved:  ${result.resolved}`);
    console.log(`  Fallback:  ${result.fallback}`);
    console.log(`  Failed:    ${result.failed}`);
    console.log(`  Skipped:   ${result.skipped}`);

    // On daily (non-incremental) runs, also retry previously failed teams
    if (!incremental) {
      const retry = await retryFailed();
      console.log('\n' + '-'.repeat(40));
      console.log('RETRY RESULTS');
      console.log(`  Resolved:     ${retry.resolved}`);
      console.log(`  Fallback:     ${retry.fallback}`);
      console.log(`  Still Failed: ${retry.stillFailed}`);
    }
  }

  const elapsed = Math.round((Date.now() - startTime) / 1000);
  console.log('\n' + '='.repeat(60));
  console.log(`DONE — ${elapsed}s`);
  console.log('='.repeat(60));

  await pool.end();
  process.exit(0);
}

main().catch((err) => {
  console.error('Fatal error:', err);
  process.exit(1);
});
