import { PointsTable } from '@core/racing/domain/value-objects/PointsTable';
import type { ChampionshipConfig } from '@core/racing/domain/types/ChampionshipConfig';
import type { SessionType } from '@core/racing/domain/types/SessionType';
import type { BonusRule } from '@core/racing/domain/types/BonusRule';
import type { DropScorePolicy } from '@core/racing/domain/types/DropScorePolicy';
import type { ChampionshipType } from '@core/racing/domain/types/ChampionshipType';
import { LeagueScoringConfig } from '@core/racing/domain/entities/LeagueScoringConfig';

export type LeagueScoringPresetPrimaryChampionshipType =
  | 'driver'
  | 'team'
  | 'nations'
  | 'trophy';

export interface LeagueScoringPreset {
  id: string;
  name: string;
  description: string;
  primaryChampionshipType: LeagueScoringPresetPrimaryChampionshipType;
  dropPolicySummary: string;
  sessionSummary: string;
  bonusSummary: string;
  createConfig: (options: { seasonId: string }) => LeagueScoringConfig;
}

const mainPointsSprintMain = new PointsTable({
  1: 25,
  2: 18,
  3: 15,
  4: 12,
  5: 10,
  6: 8,
  7: 6,
  8: 4,
  9: 2,
  10: 1,
});

const sprintPointsSprintMain = new PointsTable({
  1: 8,
  2: 7,
  3: 6,
  4: 5,
  5: 4,
  6: 3,
  7: 2,
  8: 1,
});

const clubMainPoints = new PointsTable({
  1: 20,
  2: 15,
  3: 12,
  4: 10,
  5: 8,
  6: 6,
  7: 4,
  8: 2,
  9: 1,
});

const enduranceMainPoints = new PointsTable({
  1: 50,
  2: 36,
  3: 30,
  4: 24,
  5: 20,
  6: 16,
  7: 12,
  8: 8,
  9: 4,
  10: 2,
});

export const leagueScoringPresets: LeagueScoringPreset[] = [
  {
    id: 'sprint-main-driver',
    name: 'Sprint + Main',
    description:
      'Short sprint race plus main race; sprint gives fewer points.',
    primaryChampionshipType: 'driver',
    dropPolicySummary: 'Best 6 results of 8 count towards the championship.',
    sessionSummary: 'Sprint + Main',
    bonusSummary: 'Fastest lap +1 point in main race if finishing P10 or better.',
    createConfig: ({ seasonId }) => {
      const fastestLapBonus: BonusRule = {
        id: 'fastest-lap-main',
        type: 'fastestLap',
        points: 1,
        requiresFinishInTopN: 10,
      };

      const sessionTypes: SessionType[] = ['sprint', 'main'];

      const pointsTableBySessionType: Record<SessionType, PointsTable> = {
        sprint: sprintPointsSprintMain,
        main: mainPointsSprintMain,
        practice: new PointsTable({}),
        qualifying: new PointsTable({}),
        q1: new PointsTable({}),
        q2: new PointsTable({}),
        q3: new PointsTable({}),
        timeTrial: new PointsTable({}),
      };

      const bonusRulesBySessionType: Record<SessionType, BonusRule[]> = {
        sprint: [],
        main: [fastestLapBonus],
        practice: [],
        qualifying: [],
        q1: [],
        q2: [],
        q3: [],
        timeTrial: [],
      };

      const dropScorePolicy: DropScorePolicy = {
        strategy: 'bestNResults',
        count: 6,
      };

      const championship: ChampionshipConfig = {
        id: 'driver-champ-sprint-main',
        name: 'Driver Championship',
        type: 'driver' as ChampionshipType,
        sessionTypes,
        pointsTableBySessionType,
        bonusRulesBySessionType,
        dropScorePolicy,
      };

      return LeagueScoringConfig.create({
        id: `lsc-${seasonId}-sprint-main-driver`,
        seasonId,
        scoringPresetId: 'sprint-main-driver',
        championships: [championship],
      });
    },
  },
  {
    id: 'club-default',
    name: 'Club ladder',
    description:
      'Simple club ladder with a single main race and no bonuses or drop scores.',
    primaryChampionshipType: 'driver',
    dropPolicySummary: 'All race results count, no drop scores.',
    sessionSummary: 'Main race only',
    bonusSummary: 'No bonus points.',
    createConfig: ({ seasonId }) => {
      const sessionTypes: SessionType[] = ['main'];

      const pointsTableBySessionType: Record<SessionType, PointsTable> = {
        sprint: new PointsTable({}),
        main: clubMainPoints,
        practice: new PointsTable({}),
        qualifying: new PointsTable({}),
        q1: new PointsTable({}),
        q2: new PointsTable({}),
        q3: new PointsTable({}),
        timeTrial: new PointsTable({}),
      };

      const dropScorePolicy: DropScorePolicy = {
        strategy: 'none',
      };

      const championship: ChampionshipConfig = {
        id: 'driver-champ-club-default',
        name: 'Driver Championship',
        type: 'driver' as ChampionshipType,
        sessionTypes,
        pointsTableBySessionType,
        dropScorePolicy,
      };

      return LeagueScoringConfig.create({
        id: `lsc-${seasonId}-club-default`,
        seasonId,
        scoringPresetId: 'club-default',
        championships: [championship],
      });
    },
  },
  {
    id: 'endurance-main-double',
    name: 'Endurance weekend',
    description:
      'Single main endurance race with double points and a simple drop policy.',
    primaryChampionshipType: 'driver',
    dropPolicySummary: 'Best 4 results of 6 count towards the championship.',
    sessionSummary: 'Main race only',
    bonusSummary: 'No bonus points.',
    createConfig: ({ seasonId }) => {
      const sessionTypes: SessionType[] = ['main'];

      const pointsTableBySessionType: Record<SessionType, PointsTable> = {
        sprint: new PointsTable({}),
        main: enduranceMainPoints,
        practice: new PointsTable({}),
        qualifying: new PointsTable({}),
        q1: new PointsTable({}),
        q2: new PointsTable({}),
        q3: new PointsTable({}),
        timeTrial: new PointsTable({}),
      };

      const dropScorePolicy: DropScorePolicy = {
        strategy: 'bestNResults',
        count: 4,
      };

      const championship: ChampionshipConfig = {
        id: 'driver-champ-endurance-main-double',
        name: 'Driver Championship',
        type: 'driver' as ChampionshipType,
        sessionTypes,
        pointsTableBySessionType,
        dropScorePolicy,
      };

      return {
        id: `lsc-${seasonId}-endurance-main-double`,
        seasonId,
        scoringPresetId: 'endurance-main-double',
        championships: [championship],
      };
    },
  },
];

export function listLeagueScoringPresets(): LeagueScoringPreset[] {
  return [...leagueScoringPresets];
}

export function getLeagueScoringPresetById(
  id: string,
): LeagueScoringPreset | undefined {
  return leagueScoringPresets.find((preset) => preset.id === id);
}