import { getSimulatorInfo, SIMULATOR_TYPES, type SimulatorType } from "./registry";

export type SimulatorInputKey =
  | "sourceOdds"
  | "sourceElo"
  | "worldRanking"
  | "rating"
  | "projectedWins"
  | "projectedTablePoints"
  | "seed"
  | "region"
  | "metadata";

export type SimulatorSetupSection =
  | "futuresOdds"
  | "eloRatings"
  | "rankings"
  | "ratings"
  | "regularStandings"
  | "bracket"
  | "events"
  | "golfSkills"
  | "surfaceElo"
  | "cs2Setup"
  | "participants";

export interface SimulatorManifestProfile {
  simulatorType: SimulatorType;
  displayName: string;
  description: string;
  defaultConfig: Record<string, unknown>;
  requiredInputs: SimulatorInputKey[];
  optionalInputs: SimulatorInputKey[];
  derivableInputs?: Partial<Record<SimulatorInputKey, SimulatorInputKey[]>>;
  setupSections: SimulatorSetupSection[];
  minParticipantInputs?: number;
}

const BASE_CONFIG = {
  iterations: 50_000,
};

const PROFILES: Record<SimulatorType, Omit<SimulatorManifestProfile, "simulatorType" | "displayName" | "description">> = {
  f1_standings: {
    defaultConfig: { iterations: 10_000, raceNoise: 0.5, participantVolatility: 1.5 },
    requiredInputs: ["sourceOdds"],
    optionalInputs: [],
    setupSections: ["participants", "futuresOdds", "events"],
  },
  indycar_standings: {
    defaultConfig: { iterations: 10_000, raceNoise: 0.5, participantVolatility: 1.5 },
    requiredInputs: ["sourceOdds"],
    optionalInputs: [],
    setupSections: ["participants", "futuresOdds", "events"],
  },
  golf_qualifying_points: {
    defaultConfig: { iterations: 10_000, fieldSize: 156, plBeta: 1.5 },
    requiredInputs: [],
    optionalInputs: ["sourceOdds", "rating"],
    setupSections: ["participants", "events", "golfSkills"],
  },
  playoff_bracket: {
    defaultConfig: { ...BASE_CONFIG },
    requiredInputs: ["sourceOdds"],
    optionalInputs: ["sourceElo"],
    setupSections: ["participants", "futuresOdds", "bracket"],
  },
  ucl_bracket: {
    defaultConfig: { ...BASE_CONFIG, eloWeight: 0.7, oddsWeight: 0.3 },
    requiredInputs: ["sourceOdds"],
    optionalInputs: ["sourceElo"],
    setupSections: ["participants", "futuresOdds", "bracket"],
  },
  ncaam_bracket: {
    defaultConfig: { ...BASE_CONFIG, ratingScaleFactor: 7.5, inputPolicy: { ratingMin: -10, ratingMax: 35, fallbackRatingDelta: 5 } },
    requiredInputs: ["rating"],
    optionalInputs: ["sourceOdds", "sourceElo", "seed", "region"],
    derivableInputs: { rating: ["sourceOdds"] },
    setupSections: ["participants", "ratings", "futuresOdds", "bracket"],
  },
  ncaaw_bracket: {
    defaultConfig: { ...BASE_CONFIG, inputPolicy: { ratingMin: 0.70, ratingMax: 0.97, missingRatingStrategy: "worstKnownMinus", fallbackRatingDelta: 0.01 } },
    requiredInputs: ["rating"],
    optionalInputs: ["sourceOdds", "seed", "region"],
    derivableInputs: { rating: ["sourceOdds"] },
    setupSections: ["participants", "ratings", "futuresOdds", "bracket"],
  },
  nba_bracket: {
    defaultConfig: { ...BASE_CONFIG, parityFactor: 400, seasonGames: 82 },
    requiredInputs: ["sourceElo"],
    optionalInputs: ["sourceOdds", "projectedWins"],
    derivableInputs: { sourceElo: ["projectedWins", "sourceOdds"] },
    setupSections: ["participants", "eloRatings", "regularStandings", "bracket"],
  },
  nhl_bracket: {
    defaultConfig: { ...BASE_CONFIG, parityFactor: 1000, seasonGames: 82, overtimeRate: 0.23 },
    requiredInputs: ["sourceElo"],
    optionalInputs: ["sourceOdds", "projectedWins"],
    derivableInputs: { sourceElo: ["projectedWins", "sourceOdds"] },
    setupSections: ["participants", "eloRatings", "regularStandings", "bracket"],
  },
  nfl_bracket: {
    defaultConfig: { ...BASE_CONFIG, parityFactor: 400, seasonGames: 17, homeFieldElo: 48 },
    requiredInputs: ["sourceElo"],
    optionalInputs: ["sourceOdds", "projectedWins"],
    derivableInputs: { sourceElo: ["projectedWins", "sourceOdds"] },
    setupSections: ["participants", "eloRatings", "regularStandings"],
  },
  afl_bracket: {
    defaultConfig: { ...BASE_CONFIG, parityFactor: 450, seasonGames: 23 },
    requiredInputs: ["sourceElo"],
    optionalInputs: ["projectedWins"],
    derivableInputs: { sourceElo: ["projectedWins"] },
    setupSections: ["participants", "eloRatings", "regularStandings"],
  },
  epl_standings: {
    defaultConfig: {
      ...BASE_CONFIG,
      seasonGames: 38,
      parityFactor: 400,
      matchParityFactor: 400,
      averageOpponentElo: 1500,
      baseDrawRate: 0.26,
      drawDecay: 0.002,
    },
    requiredInputs: ["sourceElo"],
    optionalInputs: ["sourceOdds", "projectedTablePoints"],
    derivableInputs: { sourceElo: ["projectedTablePoints", "sourceOdds"] },
    setupSections: ["participants", "eloRatings", "regularStandings"],
  },
  snooker_bracket: {
    defaultConfig: { ...BASE_CONFIG, eloDivisor: 400 },
    requiredInputs: ["sourceElo"],
    optionalInputs: ["worldRanking", "seed"],
    setupSections: ["participants", "eloRatings", "rankings", "bracket"],
  },
  tennis_qualifying_points: {
    defaultConfig: { iterations: 10_000, eloDivisor: 400, fallbackElo: 1500 },
    requiredInputs: [],
    optionalInputs: ["worldRanking"],
    setupSections: ["participants", "surfaceElo", "events"],
  },
  mlb_bracket: {
    defaultConfig: { ...BASE_CONFIG, rDiffWeight: 0.7, oddsWeight: 0.3, seasonGames: 162 },
    requiredInputs: ["sourceElo"],
    optionalInputs: ["sourceOdds", "projectedWins"],
    derivableInputs: { sourceElo: ["projectedWins", "sourceOdds"] },
    setupSections: ["participants", "eloRatings", "regularStandings"],
  },
  wnba_bracket: {
    defaultConfig: { ...BASE_CONFIG, seasonGames: 44, srsEloScale: 30 },
    requiredInputs: ["sourceElo"],
    optionalInputs: ["sourceOdds", "projectedWins"],
    derivableInputs: { sourceElo: ["projectedWins", "sourceOdds"] },
    setupSections: ["participants", "eloRatings", "regularStandings"],
  },
  world_cup: {
    defaultConfig: { ...BASE_CONFIG, eloWeight: 0.7, oddsWeight: 0.3 },
    requiredInputs: ["sourceElo"],
    optionalInputs: ["sourceOdds", "worldRanking"],
    derivableInputs: { sourceElo: ["sourceOdds"] },
    setupSections: ["participants", "eloRatings", "futuresOdds", "events"],
  },
  darts_bracket: {
    defaultConfig: { ...BASE_CONFIG, eloDivisor: 400 },
    requiredInputs: ["sourceElo", "worldRanking"],
    optionalInputs: ["seed"],
    setupSections: ["participants", "eloRatings", "rankings"],
  },
  cs2_major_qualifying_points: {
    defaultConfig: { iterations: 10_000, fieldSize: 32, guaranteedCount: 12 },
    requiredInputs: ["sourceElo"],
    optionalInputs: ["worldRanking", "metadata"],
    setupSections: ["participants", "eloRatings", "rankings", "cs2Setup", "events"],
  },
  ncaa_football_bracket: {
    defaultConfig: { ...BASE_CONFIG, bracketSize: 12, eloWeight: 0.6, oddsWeight: 0.4 },
    requiredInputs: ["sourceElo"],
    optionalInputs: ["sourceOdds", "worldRanking"],
    derivableInputs: { sourceElo: ["sourceOdds"] },
    setupSections: ["participants", "eloRatings", "futuresOdds", "bracket"],
  },
  llws_bracket: {
    defaultConfig: { ...BASE_CONFIG, usTeamCount: 10, internationalTeamCount: 10, poolSize: 5 },
    requiredInputs: ["sourceOdds"],
    optionalInputs: ["metadata"],
    setupSections: ["participants", "futuresOdds"],
  },
  college_hockey_bracket: {
    defaultConfig: { ...BASE_CONFIG, bracketSize: 16, parityFactor: 850 },
    requiredInputs: ["sourceElo"],
    optionalInputs: ["sourceOdds", "worldRanking"],
    derivableInputs: { sourceElo: ["sourceOdds"] },
    setupSections: ["participants", "eloRatings", "rankings", "futuresOdds", "bracket"],
  },
  brackt: {
    defaultConfig: { iterations: 20_000 },
    requiredInputs: [],
    optionalInputs: [],
    setupSections: ["participants"],
  },
  nll_bracket: {
    defaultConfig: {
      ...BASE_CONFIG,
      seasonGames: 18,
      parityFactor: 400,
      bracketSize: 8,
      playoffTeams: 8,
      regularSeasonTeamCount: 14,
      homeFieldElo: 0,
      regularSeasonMode: "project_remaining_games",
      regularSeasonNoise: 0.9,
    },
    requiredInputs: ["sourceElo"],
    optionalInputs: ["projectedWins", "sourceOdds", "seed"],
    derivableInputs: { sourceElo: ["projectedWins", "sourceOdds"] },
    setupSections: ["participants", "eloRatings", "regularStandings", "bracket"],
  },
  mls_bracket: {
    defaultConfig: {
      ...BASE_CONFIG,
      seasonGames: 34,
      parityFactor: 400,
      matchParityFactor: 400,
      averageOpponentElo: 1500,
      baseDrawRate: 0.26,
      drawDecay: 0.002,
      playoffTeamsPerConference: 9,
    },
    requiredInputs: ["sourceElo"],
    optionalInputs: ["sourceOdds", "projectedTablePoints", "seed", "region"],
    derivableInputs: { sourceElo: ["projectedTablePoints", "sourceOdds"] },
    setupSections: ["participants", "eloRatings", "regularStandings"],
  },
};

export const SIMULATOR_MANIFEST: Record<SimulatorType, SimulatorManifestProfile> =
  Object.fromEntries(
    SIMULATOR_TYPES.map((simulatorType) => {
      const info = getSimulatorInfo(simulatorType);
      const profile = PROFILES[simulatorType];
      return [
        simulatorType,
        {
          simulatorType,
          displayName: info?.name ?? simulatorType,
          description: info?.description ?? "",
          ...profile,
          minParticipantInputs: profile.minParticipantInputs ?? 1,
        },
      ];
    })
  ) as Record<SimulatorType, SimulatorManifestProfile>;

export function getManifestSimulatorProfile(
  simulatorType: SimulatorType
): SimulatorManifestProfile {
  return SIMULATOR_MANIFEST[simulatorType];
}

export function simulatorInputLabel(key: SimulatorInputKey): string {
  const labels: Record<SimulatorInputKey, string> = {
    sourceOdds: "futures odds",
    sourceElo: "Elo rating",
    worldRanking: "ranking",
    rating: "rating",
    projectedWins: "projected wins",
    projectedTablePoints: "projected table points",
    seed: "seed",
    region: "region",
    metadata: "metadata",
  };
  return labels[key];
}
