import 'dotenv/config';
import fs from 'fs';
import os from 'os';
import path from 'path';
import pool from '../db';
import { getCurrentEtDateKey } from '../lib/league-windows';
import { getSupportedPlayerPropTypes } from '../services/player-prop-market-registry';
import {
  buildPlayerPropCandidateAuditReport,
  renderPlayerPropCandidateAuditMarkdown,
  type PlayerPropCandidateAuditEventInput,
  type PlayerPropCandidateAuditSideReport,
} from '../services/player-prop-candidate-audit';
import { fetchTeamPropMarketCandidates } from '../services/team-prop-market-candidates';

interface EventRow {
  event_id: string;
  league: string;
  home_team: string;
  home_short: string;
  away_team: string;
  away_short: string;
  starts_at: string;
}

const args = process.argv.slice(2);

function hasFlag(flag: string): boolean {
  return args.includes(flag);
}

function getArgValue(flag: string): string | null {
  const index = args.indexOf(flag);
  if (index === -1) return null;
  return args[index + 1] || null;
}

function buildTimestampSlug(date: Date): string {
  return date.toISOString().replace(/[:.]/g, '-');
}

function buildOutputPaths(outputDir: string, auditedAt: Date): { jsonPath: string; markdownPath: string } {
  const slug = buildTimestampSlug(auditedAt);
  return {
    jsonPath: path.join(outputDir, `player-prop-candidate-audit-${slug}.json`),
    markdownPath: path.join(outputDir, `player-prop-candidate-audit-${slug}.md`),
  };
}

function isLeagueAuditable(league: string, includeMlb: boolean): boolean {
  const normalized = String(league || '').toLowerCase();
  if (!normalized) return false;
  if (!includeMlb && normalized === 'mlb') return false;
  return getSupportedPlayerPropTypes(normalized).length > 0;
}

function summarizeTopStatTypes(candidates: Array<{ normalizedStatType?: string; statType?: string }>): Array<{ statType: string; count: number }> {
  const counts = new Map<string, number>();
  for (const candidate of candidates) {
    const statType = String(candidate.normalizedStatType || candidate.statType || '').trim();
    if (!statType) continue;
    counts.set(statType, (counts.get(statType) || 0) + 1);
  }

  return [...counts.entries()]
    .sort((a, b) => {
      const countDelta = b[1] - a[1];
      if (countDelta !== 0) return countDelta;
      return a[0].localeCompare(b[0]);
    })
    .slice(0, 5)
    .map(([statType, count]) => ({ statType, count }));
}

async function auditTeamSide(params: {
  league: string;
  teamName: string;
  teamShort: string;
  opponentName: string;
  opponentShort: string;
  startsAt: string;
  homeTeam: string;
  awayTeam: string;
  verifyTheOdds: boolean;
}): Promise<PlayerPropCandidateAuditSideReport> {
  const candidates = await fetchTeamPropMarketCandidates({
    league: params.league,
    teamName: params.teamName,
    teamShort: params.teamShort,
    opponentName: params.opponentName,
    opponentShort: params.opponentShort,
    startsAt: params.startsAt,
    homeTeam: params.homeTeam,
    awayTeam: params.awayTeam,
    skipTheOddsVerification: !params.verifyTheOdds,
  });

  const twoWayCandidateCount = candidates.filter((candidate) => candidate.availableSides.length === 2).length;
  const oneWayCandidateCount = candidates.length - twoWayCandidateCount;
  const gapFilledCandidateCount = candidates.filter((candidate) => candidate.isGapFilled).length;

  return {
    teamName: params.teamName,
    teamShort: params.teamShort,
    candidateCount: candidates.length,
    twoWayCandidateCount,
    oneWayCandidateCount,
    gapFilledCandidateCount,
    topStatTypes: summarizeTopStatTypes(candidates),
  };
}

async function fetchScopedEvents(dateEt: string, leagueFilter: string | null, includeMlb: boolean): Promise<EventRow[]> {
  const params: any[] = [dateEt];
  const where: string[] = [
    `(starts_at AT TIME ZONE 'America/New_York')::date = $1::date`,
  ];

  if (leagueFilter) {
    params.push(leagueFilter.toLowerCase());
    where.push(`LOWER(league) = $${params.length}`);
  }

  const { rows } = await pool.query(
    `SELECT event_id, league, home_team, home_short, away_team, away_short, starts_at
     FROM rm_events
     WHERE ${where.join(' AND ')}
     ORDER BY starts_at ASC`,
    params,
  );

  return rows.filter((row: EventRow) => isLeagueAuditable(row.league, includeMlb));
}

async function main() {
  const auditedAt = new Date();
  const dateEt = getArgValue('--date') || getCurrentEtDateKey(auditedAt);
  const leagueFilter = getArgValue('--league');
  const outputDir = getArgValue('--output-dir') || path.join(os.tmpdir(), 'rainmaker-prop-audits');
  const includeMlb = hasFlag('--include-mlb');
  const verifyTheOdds = hasFlag('--verify-theodds');
  const failOnFindings = !hasFlag('--no-fail-on-findings');

  const events = await fetchScopedEvents(dateEt, leagueFilter, includeMlb);
  const auditEvents: PlayerPropCandidateAuditEventInput[] = [];

  for (const event of events) {
    const homeTeam = event.home_team;
    const awayTeam = event.away_team;
    const [home, away] = await Promise.all([
      auditTeamSide({
        league: event.league,
        teamName: event.home_team,
        teamShort: event.home_short,
        opponentName: event.away_team,
        opponentShort: event.away_short,
        startsAt: event.starts_at,
        homeTeam,
        awayTeam,
        verifyTheOdds,
      }),
      auditTeamSide({
        league: event.league,
        teamName: event.away_team,
        teamShort: event.away_short,
        opponentName: event.home_team,
        opponentShort: event.home_short,
        startsAt: event.starts_at,
        homeTeam,
        awayTeam,
        verifyTheOdds,
      }),
    ]);

    auditEvents.push({
      league: event.league,
      eventId: event.event_id,
      matchup: `${event.away_short} @ ${event.home_short}`,
      startsAt: event.starts_at,
      home,
      away,
    });
  }

  const report = buildPlayerPropCandidateAuditReport({
    auditedAt: auditedAt.toISOString(),
    events: auditEvents,
  });

  fs.mkdirSync(outputDir, { recursive: true });
  const { jsonPath, markdownPath } = buildOutputPaths(outputDir, auditedAt);
  fs.writeFileSync(jsonPath, JSON.stringify(report, null, 2));
  fs.writeFileSync(markdownPath, renderPlayerPropCandidateAuditMarkdown(report));

  console.log(JSON.stringify({
    auditedAt: report.auditedAt,
    scope: leagueFilter ? `league:${leagueFilter.toLowerCase()}` : `date_et:${dateEt}`,
    includeMlb,
    verifyTheOdds,
    passed: report.passed,
    summary: report.summary,
    jsonPath,
    markdownPath,
  }, null, 2));

  await pool.end();
  if (failOnFindings && !report.passed) {
    process.exit(1);
  }
}

if (require.main === module) {
  main().catch(async (err) => {
    console.error('[player-prop-candidate-audit] Fatal:', err);
    await pool.end().catch(() => {});
    process.exit(1);
  });
}
