function toNumber(value: any): number | null {
  if (value == null || value === '') return null;
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : null;
}

function resolveForecastSideKey(
  forecastData: any,
  homeTeam: string | null | undefined,
  awayTeam: string | null | undefined,
): 'home' | 'away' | null {
  const forecastSide = String(forecastData?.forecast_side || forecastData?.winner_pick || '').trim();
  if (!forecastSide) return null;
  if (homeTeam && forecastSide === homeTeam) return 'home';
  if (awayTeam && forecastSide === awayTeam) return 'away';
  return null;
}

function cleanTeamLabel(value: any): string | null {
  const text = String(value || '').trim();
  return text || null;
}

export interface PublicGameFitInput {
  league?: string | null;
  forecastData?: any;
  homeTeam?: string | null;
  awayTeam?: string | null;
}

export interface PublicGameFitProfile {
  eligible: boolean;
  modelMoneyline: number | null;
  spreadEdge: number | null;
}

export function assessPublicGameFit(input: PublicGameFitInput): PublicGameFitProfile {
  const league = String(input.league || '').trim().toLowerCase();
  const forecastData = input.forecastData || null;
  if (!forecastData) {
    return { eligible: false, modelMoneyline: null, spreadEdge: null };
  }

  const spreadEdge = toNumber(forecastData.spread_edge);
  const sideKey = resolveForecastSideKey(forecastData, input.homeTeam, input.awayTeam);
  const forecastSide = cleanTeamLabel(forecastData?.forecast_side);
  const winnerPick = cleanTeamLabel(forecastData?.winner_pick);
  const isSplitForecast = Boolean(forecastSide && winnerPick && forecastSide !== winnerPick);
  const modelMoneyline = sideKey
    ? toNumber(forecastData?.projected_lines?.moneyline?.[sideKey])
    : null;

  if (league !== 'mlb') {
    return {
      eligible: true,
      modelMoneyline,
      spreadEdge,
    };
  }

  // MLB split forecasts (favorite wins outright, dog/runline side has value)
  // materially outperform the aligned bucket. Keep those as long as the value
  // side is not a heavy favorite. For aligned MLB forecasts, stay selective:
  // light price and moderate edge only.
  const eligible = modelMoneyline != null
    && modelMoneyline > -130
    && (
      isSplitForecast
      || (spreadEdge != null && spreadEdge < 3)
    );

  return {
    eligible,
    modelMoneyline,
    spreadEdge,
  };
}
