export const FORECAST_PUBLIC_CONTRACT_VERSION = 'forecast-public-v1' as const;

/**
 * Deprecated aliases are v1 backward-compat only. Do not add new aliases
 * without updating the shared alias maps, serializers, and drift tests.
 */
export const DEPRECATED_FORECAST_RESPONSE_ALIAS_MAP = {
  forecast_balance: 'forecastBalance',
} as const;

export const DEPRECATED_FORECAST_RESPONSE_FIELDS = Object.keys(
  DEPRECATED_FORECAST_RESPONSE_ALIAS_MAP,
) as Array<keyof typeof DEPRECATED_FORECAST_RESPONSE_ALIAS_MAP>;

/**
 * Deprecated player-prop aliases remain public in v1 only to avoid breaking
 * older consumers. Canonical public fields are the camelCase targets below.
 */
export const DEPRECATED_PLAYER_PROP_ALIAS_MAP = {
  prob: 'projectedProbability',
  line: 'marketLineValue',
  projected_stat_value: 'projectedOutcome',
  stat_type: 'statType',
  normalized_stat_type: 'normalizedStatType',
  market_line_value: 'marketLineValue',
} as const;

export const DEPRECATED_PLAYER_PROP_FIELDS = Object.keys(
  DEPRECATED_PLAYER_PROP_ALIAS_MAP,
) as Array<keyof typeof DEPRECATED_PLAYER_PROP_ALIAS_MAP>;

export type PublicMarketSourceType = 'sportsbook' | 'feed' | 'provider' | 'unknown';

export interface PublicForecastBalanceFields {
  forecastBalance: number;
  forecast_balance: number;
}

export interface PublicInsightAvailability {
  steam: boolean;
  sharp: boolean;
  dvp: boolean;
  hcw: boolean;
}

export interface PublicMlbPhaseContext {
  phaseLabel: string | null;
  kRank: number | null;
  lineupCertainty: string | null;
  parkFactor: number | null;
  weatherImpact: string | null;
}

export interface PublicMlbMatchupContext {
  log5HomeWinProb: number | null;
  impliedSpread: number | null;
  strengthDiff: string | null;
  parkRunsFactor: number | null;
  parkHrFactor: number | null;
  homeRunsCreated: number | null;
  awayRunsCreated: number | null;
  homePythagWinPct: number | null;
  awayPythagWinPct: number | null;
  homeProjectedWrcPlus: number | null;
  awayProjectedWrcPlus: number | null;
  homeTeamWrcPlus: number | null;
  awayTeamWrcPlus: number | null;
  homeStarterFip: number | null;
  awayStarterFip: number | null;
}

export interface PublicMlbPropContext {
  kRank: number | null;
  parkFactor: number | null;
  weatherImpact: string | null;
  handednessSplit?: string | null;
  lineupCertainty?: string | null;
}

export interface PublicForecastPropHighlight {
  player: string | null;
  prop: string | null;
  recommendation: string | null;
  reasoning: string | null;
}

export interface PublicForecastProjectedLines {
  moneyline?: { home: number | null; away: number | null } | null;
  spread?: { home: number | null; away: number | null } | null;
  total?: number | null;
}

export interface PublicForecastModelSignals {
  piff?: {
    avgEdge?: number | null;
    legCount?: number | null;
    topPicks?: Array<{
      name?: string | null;
      stat?: string | null;
      line?: number | null;
      edge?: number | null;
      direction?: string | null;
      tier?: string | null;
      szn_hr?: number | null;
    }> | null;
  } | null;
  digimon?: {
    available?: boolean;
    lockCount?: number | null;
    avgMissRate?: number | null;
    topPicks?: Array<{
      player?: string | null;
      prop?: string | null;
      line?: number | null;
      missRate?: number | null;
      verdict?: string | null;
    }> | null;
  } | null;
  dvp?: {
    home?: Record<string, unknown> | null;
    away?: Record<string, unknown> | null;
  } | null;
  grok?: {
    confidence?: number | null;
    valueRating?: number | null;
  } | null;
}

export interface PublicForecastInputQuality {
  piff?: { grade?: string | null; legs?: number | null; avgEdge?: number | null } | null;
  dvp?: { grade?: string | null; stats?: number | null; freshness?: string | null } | null;
  digimon?: { grade?: string | null; lockCount?: number | null; reason?: string | null } | null;
  odds?: { grade?: string | null; markets?: number | null } | null;
  rag?: { grade?: string | null; chunks?: number | null } | null;
  overall?: string | null;
}

export interface PublicTeamForecastEngine {
  code: string;
  label: string;
  detail?: string | null;
  applied: boolean;
}

/**
 * `forecast` stays a legacy bag in v1. Known nested structures are normalized
 * through a serializer boundary, but snake_case keys inside this object remain
 * part of the legacy contract until v2.
 */
export interface PublicForecastLegacyPayloadV1 extends Record<string, unknown> {
  winner_pick?: string | null;
  forecast_side?: string | null;
  projected_winner?: string | null;
  summary?: string | null;
  key_factors?: Array<string | null> | null;
  prop_highlights?: PublicForecastPropHighlight[] | null;
  projected_lines?: PublicForecastProjectedLines | null;
  total_direction?: string | null;
  value_rating?: number | null;
  spread_edge?: number | null;
  mlb_phase_context?: {
    phase_label?: string | null;
    k_rank?: number | null;
    lineup_certainty?: string | null;
    park_factor?: number | null;
    weather_impact?: string | null;
  } | null;
  mlb_matchup_context?: {
    log5_home_win_prob?: number | null;
    implied_spread?: number | null;
    strength_diff?: string | null;
    park_runs_factor?: number | null;
    park_hr_factor?: number | null;
    home_runs_created?: number | null;
    away_runs_created?: number | null;
    home_pythag_win_pct?: number | null;
    away_pythag_win_pct?: number | null;
    home_projected_wrc_plus?: number | null;
    away_projected_wrc_plus?: number | null;
    home_team_wrc_plus?: number | null;
    away_team_wrc_plus?: number | null;
    home_starter_fip?: number | null;
    away_starter_fip?: number | null;
  } | null;
}

export interface PublicGroupedPlayerPropRow {
  propType: string;
  marketLine: number | null;
  odds: number | null;
  marketImpliedProbability: number | null;
  forecastDirection: 'OVER' | 'UNDER';
  projectedProbability: number | null;
  projectedOutcome: number | null;
  edgePct: number | null;
  signal: 'FAIR' | 'GOOD' | 'STRONG';
}

export interface PublicGroupedPlayer {
  player: string;
  team: string | null;
  teamSide: 'home' | 'away' | null;
  playerRole: string | null;
  strongestSignal: 'FAIR' | 'GOOD' | 'STRONG';
  maxEdgePct: number;
  props: PublicGroupedPlayerPropRow[];
}

export interface PublicDigiviewEvidence {
  last5Samples?: Array<{
    gameDate?: string | null;
    opponent?: string | null;
    value?: number | null;
    hit?: boolean | null;
  }> | null;
  last10Samples?: Array<{
    gameDate?: string | null;
    opponent?: string | null;
    value?: number | null;
    hit?: boolean | null;
  }> | null;
  h2hSamples?: Array<{
    gameDate?: string | null;
    opponent?: string | null;
    value?: number | null;
    hit?: boolean | null;
  }> | null;
  historyWindows?: Array<{
    label: string;
    average?: number | null;
    hitRatePct?: number | null;
    sampleSize?: number | null;
  }> | null;
  tierLabel?: string | null;
  seasonAverage?: number | null;
  last5Average?: number | null;
  last10Average?: number | null;
  seasonHitRatePct?: number | null;
  last5HitRatePct?: number | null;
  last10HitRatePct?: number | null;
  projectedMinutes?: number | null;
  isHome?: boolean | null;
  isBackToBack?: boolean | null;
  dvpTier?: string | null;
  dvpRank?: number | null;
  dvpAdjustment?: number | null;
  dvpAligned?: boolean | null;
  dvpMisaligned?: boolean | null;
  h2hGames?: number | null;
  h2hHitRatePct?: number | null;
  h2hFlag?: string | null;
  missRatePct?: number | null;
  misses?: string | null;
  injuryContext?: string | null;
  volatility?: number | null;
  contextSummary?: string | null;
  commentary?: string | null;
  lineSource?: string | null;
  availableBooks?: number | null;
  lineupStatus?: string | null;
  lineupCertainty?: string | null;
  lineupSource?: string | null;
  gapValue?: number | null;
  decisionContext?: string | null;
  digimonVerdict?: string | null;
  digimonLine?: number | null;
  lockGate?: 'pass' | 'fail' | null;
}

export interface PublicPlayerProp {
  assetId: string;
  player: string | null;
  team: string | null;
  teamSide: 'home' | 'away' | null;
  league: string | null;
  prop: string | null;
  locked: boolean;
  recommendation?: string | null;
  reasoning?: string | null;
  edge?: number | null;
  prob?: number | null;
  line?: number | null;
  odds?: number | null;
  confidence: number | null;
  projected_stat_value?: number | null;
  stat_type?: string | null;
  normalized_stat_type?: string | null;
  market_line_value?: number | null;
  projectedOutcome?: number | null;
  statType?: string | null;
  normalizedStatType?: string | null;
  marketLine?: number | null;
  marketLineValue?: number | null;
  gradingCategory?: string | null;
  signalTier?: 'FAIR' | 'GOOD' | 'STRONG';
  forecastDirection?: 'OVER' | 'UNDER';
  marketImpliedProbability?: number;
  projectedProbability?: number;
  agreementScore?: number;
  agreementLabel?: 'LOW' | 'MEDIUM' | 'HIGH';
  agreementSources?: string[];
  marketQualityScore?: number;
  marketQualityLabel?: 'WEAK' | 'FAIR' | 'GOOD' | 'STRONG';
  marketCompletenessStatus?: 'source_complete' | 'multi_source_complete' | 'incomplete' | null;
  /**
   * Legacy UI convenience field. When present it should mirror
   * `signalTableRow.edgePct`.
   */
  edgePct?: number | null;
  signalTableRow?: PublicGroupedPlayerPropRow;
  marketType?: string | null;
  marketFamily?: string | null;
  marketOrigin?: string | null;
  sourceBacked?: boolean | null;
  playerRole?: string | null;
  modelContext?: Record<string, any> | null;
  mlbPropContext?: PublicMlbPropContext | null;
  digiview?: PublicDigiviewEvidence | null;
  resultOutcome?: string | null;
  closingLineValue?: number | null;
  closingOddsSnapshot?: number | null;
}

export interface PublicPlayerPropMarket {
  player: string | null;
  team: string | null;
  teamSide: 'home' | 'away' | null;
  prop: string | null;
  marketType?: string | null;
  line: number | null;
  overOdds: number | null;
  underOdds: number | null;
  completenessStatus?: string | null;
  source?: string | null;
  books?: number | null;
  playerRole?: string | null;
}

export interface PublicFeaturedPlayerProp {
  assetId: string;
  propType: string;
  propLabel: string | null;
  marketLine: number | null;
  odds: number | null;
  forecastDirection: 'OVER' | 'UNDER' | null;
  projectedOutcome: number | null;
  projectedProbability: number | null;
  marketImpliedProbability: number | null;
  varianceEdgePct: number | null;
  varianceSignal: 'COIN_FLIP' | 'FAIR' | 'GOOD' | 'STRONG' | null;
  hasPick: boolean;
  signalTier?: 'FAIR' | 'GOOD' | 'STRONG' | null;
  locked: boolean;
  analysis: string | null;
}

export interface PublicFeaturedPlayer {
  player: string;
  team: string | null;
  teamSide: 'home' | 'away' | null;
  playerRole: string | null;
  availability: 'confirmed' | 'projected' | 'active' | 'unknown';
  projectedMinutes: number | null;
  signalStrength: 'COIN_FLIP' | 'FAIR' | 'GOOD' | 'STRONG' | null;
  maxVarianceEdgePct: number | null;
  hasPick: boolean;
  analysis: string | null;
  props: PublicFeaturedPlayerProp[];
}

export interface PublicTopPropCard {
  assetId: string;
  eventId: string;
  league: string | null;
  startsAt: string | null;
  playerName: string;
  team: string | null;
  opponent: string | null;
  propType: string;
  marketLine: number | null;
  odds: number | null;
  marketImpliedProbability: number;
  forecastDirection: 'OVER' | 'UNDER';
  projectedProbability: number;
  projectedOutcome: number | null;
  edgePct: number;
  signal: 'FAIR' | 'GOOD' | 'STRONG';
  agreementLabel: 'LOW' | 'MEDIUM' | 'HIGH';
  marketQualityLabel: 'WEAK' | 'FAIR' | 'GOOD' | 'STRONG';
  clvFitLabel: 'TRACKED' | 'CAUTION';
  clvFitScore: number;
  clvTracked: boolean;
  closingLineValue?: number | null;
  verificationLabel?: string | null;
  verificationType?: PublicMarketSourceType | null;
  rankScore: number;
  rankPosition: number;
}

export interface PublicTopGameCard {
  eventId: string;
  league: string | null;
  startsAt: string | null;
  homeTeam: string;
  awayTeam: string;
  homeShort: string | null;
  awayShort: string | null;
  forecastSide: string | null;
  confidencePct: number;
  edge: number | null;
  valueRating: number;
  hasSharpSignal: boolean;
  hasSteamSignal: boolean;
  verificationLabel?: string | null;
  verificationType?: PublicMarketSourceType | null;
}

export interface PublicTopPickEntry {
  kind: 'prop' | 'game';
  rankPosition: number;
  boardScore: number;
  clvMetric: number;
  edgeMetric: number;
  confidenceMetric: number;
  signalMetric: number;
  prop?: PublicTopPropCard;
  game?: PublicTopGameCard;
}

export interface PublicForecastResponseV1 extends PublicForecastBalanceFields {
  contractVersion: typeof FORECAST_PUBLIC_CONTRACT_VERSION;
  forecast: PublicForecastLegacyPayloadV1;
  confidence: number | null;
  homeTeam: string;
  awayTeam: string;
  homeShort?: string;
  awayShort?: string;
  league: string;
  alreadyOwned: boolean;
  odds?: unknown;
  openingLines?: unknown;
  modelLines?: unknown;
  compositeConfidence?: number | null;
  forecastVersion: string | null;
  staticCommit: true;
  generatedAt: string | null;
  lastRefreshAt?: string | null;
  lastRefreshType?: string | null;
  materialChange?: unknown;
  insightAvailability?: PublicInsightAvailability;
  unlockedInsights?: string[];
  unlockedInsightData?: Record<string, unknown>;
  basemonSummary?: unknown;
  modelSignals?: PublicForecastModelSignals | null;
  inputQuality?: PublicForecastInputQuality | null;
  teamForecastEngine?: PublicTeamForecastEngine | null;
  rieSignals?: unknown[];
  ragInsights?: unknown[];
  strategyId?: string;
  mlbPhaseContext?: PublicMlbPhaseContext | null;
  mlbMatchupContext?: PublicMlbMatchupContext | null;
}

export interface PublicForecastNotReadyResponseV1 {
  contractVersion: typeof FORECAST_PUBLIC_CONTRACT_VERSION;
  status: 'not_ready';
  message: string;
  eventId: string;
  homeTeam: string;
  awayTeam: string;
  homeShort?: string;
  awayShort?: string;
  league: string;
  odds?: unknown;
  insightAvailability: PublicInsightAvailability;
  unlockedInsights: string[];
  unlockedInsightData: Record<string, unknown>;
}

export interface PublicPlayerPropsResponseV1 extends PublicForecastBalanceFields {
  contractVersion: typeof FORECAST_PUBLIC_CONTRACT_VERSION;
  playerProps: PublicPlayerProp[];
  marketProps: PublicPlayerPropMarket[];
  players: PublicGroupedPlayer[];
  featuredPlayers: PublicFeaturedPlayer[];
  count: number;
  mode: 'per_player' | 'team';
  fallbackReason: 'no_precomputed_assets' | 'all_assets_filtered_out' | 'game_started' | null;
}

export interface PublicTopPropsResponseV1 {
  contractVersion: typeof FORECAST_PUBLIC_CONTRACT_VERSION;
  league: string;
  generatedAt: string;
  count: number;
  cards: PublicTopPropCard[];
  filters: {
    propTypes: string[];
    teams: string[];
    players: string[];
  };
  emptyMessage: string;
}

export interface PublicTopPicksResponseV1 {
  contractVersion: typeof FORECAST_PUBLIC_CONTRACT_VERSION;
  league: string;
  generatedAt: string;
  count: number;
  entries: PublicTopPickEntry[];
  filters: {
    propTypes: string[];
    teams: string[];
    players: string[];
    kinds: Array<'prop' | 'game'>;
  };
  emptyMessage: string;
}
