import 'dotenv/config';
import pool from '../db';
import {
  extractMlbDirectFeatures,
  MLB_DIRECT_MODEL_LIVE_CONFIG,
  MLB_DIRECT_MODEL_LIVE_POLICY,
  scoreMlbDirectModel,
} from '../services/mlb-team-direct-model';
import type { SignalResult } from '../services/rie/types';

function getArg(flag: string): string | null {
  const idx = process.argv.indexOf(flag);
  return idx >= 0 && idx + 1 < process.argv.length ? process.argv[idx + 1] : null;
}

function etDateKey(date = new Date()): string {
  return new Intl.DateTimeFormat('en-CA', {
    timeZone: 'America/New_York',
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
  }).format(date);
}

type SlateRow = {
  event_id: string;
  league: string;
  home_team: string;
  away_team: string;
  starts_at: string;
  odds_data: any;
  forecast_data: any;
  model_signals: any;
  composite_confidence: number | null;
  confidence_score: number | null;
};

type AuditRow = {
  eventId: string;
  startsAt: string;
  homeTeam: string;
  awayTeam: string;
  enginePath: 'mlb_direct_model' | 'mlb_baseline_fallback';
  cachedWinnerPick: string | null;
  cachedConfidence: number | null;
  directWinnerPick: string | null;
  directConfidence: number | null;
  featureCoverageScore: number | null;
  recommendedMarket: string | null;
  currentPolicyPath: 'mlb_direct_model' | 'mlb_baseline_fallback';
  pathDrift: boolean;
  abstainReasons: string[];
};

function normalizeSignals(modelSignals: any): SignalResult[] {
  const payload = typeof modelSignals === 'string' ? JSON.parse(modelSignals) : (modelSignals || {});
  return Array.isArray(payload?.rieSignals) ? payload.rieSignals : [];
}

function coverageScore(featureCoverage: Record<string, boolean> | null | undefined): number | null {
  if (!featureCoverage) return null;
  const values = Object.values(featureCoverage);
  if (!values.length) return null;
  return Math.round(((values.filter(Boolean).length / values.length) * 1000)) / 1000;
}

async function loadSlate(dateKey: string): Promise<SlateRow[]> {
  const { rows } = await pool.query(
    `SELECT event_id, league, home_team, away_team, starts_at,
            odds_data, forecast_data, model_signals,
            composite_confidence, confidence_score
       FROM rm_forecast_cache
      WHERE league = 'mlb'
        AND (starts_at AT TIME ZONE 'America/New_York')::date = $1::date
      ORDER BY starts_at ASC, event_id ASC`,
    [dateKey],
  );
  return rows as SlateRow[];
}

function auditRow(row: SlateRow): AuditRow {
  const forecastData = typeof row.forecast_data === 'string' ? JSON.parse(row.forecast_data) : (row.forecast_data || {});
  const signals = normalizeSignals(row.model_signals);
  const featureVector = extractMlbDirectFeatures({
    signals,
    oddsData: row.odds_data || {},
  });
  const decision = scoreMlbDirectModel({
    homeTeam: row.home_team,
    awayTeam: row.away_team,
    featureVector,
    config: MLB_DIRECT_MODEL_LIVE_CONFIG,
    policy: MLB_DIRECT_MODEL_LIVE_POLICY,
  });
  const directApplied = Boolean(forecastData?.mlb_direct_model?.applied);
  const currentPolicyPath = decision.available && decision.policy.shouldBet && decision.policy.recommendedMarket === 'moneyline'
    ? 'mlb_direct_model'
    : 'mlb_baseline_fallback';
  return {
    eventId: row.event_id,
    startsAt: row.starts_at,
    homeTeam: row.home_team,
    awayTeam: row.away_team,
    enginePath: directApplied ? 'mlb_direct_model' : 'mlb_baseline_fallback',
    cachedWinnerPick: forecastData?.winner_pick || null,
    cachedConfidence: row.composite_confidence ?? row.confidence_score ?? null,
    directWinnerPick: decision.available ? decision.winnerPick : null,
    directConfidence: decision.available ? decision.confidence : null,
    featureCoverageScore: coverageScore(featureVector.featureCoverage),
    recommendedMarket: decision.policy.recommendedMarket || null,
    currentPolicyPath,
    pathDrift: currentPolicyPath !== (directApplied ? 'mlb_direct_model' : 'mlb_baseline_fallback'),
    abstainReasons: directApplied ? [] : decision.policy.reasons,
  };
}

async function main() {
  const dateKey = getArg('--date') || etDateKey();
  const json = process.argv.includes('--json');
  const rows = await loadSlate(dateKey);
  const audited = rows.map(auditRow);

  if (json) {
    console.log(JSON.stringify({ date: dateKey, count: audited.length, rows: audited }, null, 2));
    return;
  }

  console.log(`MLB live slate audit for ${dateKey}`);
  console.log(`rows=${audited.length}`);
  if (!audited.length) {
    console.log('No MLB cache rows for that ET date.');
    return;
  }

  for (const row of audited) {
    const abstain = row.abstainReasons.length ? ` abstain=${row.abstainReasons.join(' | ')}` : '';
    const drift = row.pathDrift ? ` drift=current:${row.currentPolicyPath}` : '';
    console.log(
      `${row.startsAt} ${row.eventId} engine=${row.enginePath} ` +
      `cached=${row.cachedWinnerPick || 'null'} conf=${row.cachedConfidence ?? 'null'} ` +
      `direct=${row.directWinnerPick || 'null'} direct_conf=${row.directConfidence ?? 'null'} ` +
      `coverage=${row.featureCoverageScore ?? 'null'} market=${row.recommendedMarket ?? 'null'}${drift}${abstain}`
    );
  }
}

main()
  .catch((error) => {
    console.error('[mlb-team-live-slate-audit] failed', error);
    process.exit(1);
  })
  .finally(async () => {
    await pool.end().catch(() => undefined);
  });
