import { League } from '@core/racing/domain/entities/League';
import { LeagueScoringConfig } from '@core/racing/domain/entities/LeagueScoringConfig';
import { Season } from '@core/racing/domain/entities/season/Season';
import { PointsTable } from '@core/racing/domain/value-objects/PointsTable';
import { beforeEach, describe, expect, it } from 'vitest';
import { CreateLeaguePresenter } from './CreateLeaguePresenter';

describe('CreateLeaguePresenter', () => {
  let presenter: CreateLeaguePresenter;

  beforeEach(() => {
    presenter = new CreateLeaguePresenter();
  });

  describe('present', () => {
    it('should present successful league creation', () => {
      const league = League.create({
        id: 'league-1',
        name: 'Test League',
        description: 'A test league',
        ownerId: 'owner-1',
        settings: { pointsSystem: 'f1-2024' },
      });

      const season = Season.create({
        id: 'season-1',
        leagueId: 'league-1',
        gameId: 'iracing',
        name: 'Test League Season 1',
        status: 'active',
      } as never);

      const scoringConfig = LeagueScoringConfig.create({
        id: 'scoring-1',
        seasonId: 'season-1',
        scoringPresetId: 'preset-1',
        championships: [
          {
            id: 'champ-1',
            name: 'Driver Championship',
            type: 'driver',
            sessionTypes: ['main'],
            pointsTableBySessionType: {
              practice: new PointsTable({}),
              qualifying: new PointsTable({}),
              q1: new PointsTable({}),
              q2: new PointsTable({}),
              q3: new PointsTable({}),
              sprint: new PointsTable({}),
              main: new PointsTable({ 1: 25, 2: 18, 3: 15 }),
              timeTrial: new PointsTable({}),
            },
            dropScorePolicy: { strategy: 'none' },
          },
        ],
      });

      presenter.present({ league, season, scoringConfig });

      const vm = presenter.getViewModel();

      expect(vm).toEqual({
        leagueId: 'league-1',
        success: true,
      });
    });

    it('should present league with different ID', () => {
      const league = League.create({
        id: 'league-abc-123',
        name: 'Another League',
        description: 'Another test league',
        ownerId: 'owner-2',
        settings: { pointsSystem: 'indycar' },
      });

      const season = Season.create({
        id: 'season-2',
        leagueId: 'league-abc-123',
        gameId: 'iracing',
        name: 'Another League Season 1',
        status: 'active',
      } as never);

      const scoringConfig = LeagueScoringConfig.create({
        id: 'scoring-2',
        seasonId: 'season-2',
        scoringPresetId: 'preset-2',
        championships: [
          {
            id: 'champ-2',
            name: 'Driver Championship',
            type: 'driver',
            sessionTypes: ['main'],
            pointsTableBySessionType: {
              practice: new PointsTable({}),
              qualifying: new PointsTable({}),
              q1: new PointsTable({}),
              q2: new PointsTable({}),
              q3: new PointsTable({}),
              sprint: new PointsTable({}),
              main: new PointsTable({ 1: 25, 2: 18, 3: 15 }),
              timeTrial: new PointsTable({}),
            },
            dropScorePolicy: { strategy: 'none' },
          },
        ],
      });

      presenter.present({ league, season, scoringConfig });

      const vm = presenter.getViewModel();

      expect(vm).toEqual({
        leagueId: 'league-abc-123',
        success: true,
      });
    });
  });

  describe('getViewModel', () => {
    it('should throw error when not presented', () => {
      expect(() => presenter.getViewModel()).toThrow('Presenter not presented');
    });

    it('should return the model when presented', () => {
      const league = League.create({
        id: 'league-1',
        name: 'Test League',
        description: 'A test league',
        ownerId: 'owner-1',
        settings: { pointsSystem: 'f1-2024' },
      });

      const season = Season.create({
        id: 'season-1',
        leagueId: 'league-1',
        gameId: 'iracing',
        name: 'Test League Season 1',
        status: 'active',
      } as never);

      const scoringConfig = LeagueScoringConfig.create({
        id: 'scoring-1',
        seasonId: 'season-1',
        scoringPresetId: 'preset-1',
        championships: [
          {
            id: 'champ-1',
            name: 'Driver Championship',
            type: 'driver',
            sessionTypes: ['main'],
            pointsTableBySessionType: {
              practice: new PointsTable({}),
              qualifying: new PointsTable({}),
              q1: new PointsTable({}),
              q2: new PointsTable({}),
              q3: new PointsTable({}),
              sprint: new PointsTable({}),
              main: new PointsTable({ 1: 25, 2: 18, 3: 15 }),
              timeTrial: new PointsTable({}),
            },
            dropScorePolicy: { strategy: 'none' },
          },
        ],
      });

      presenter.present({ league, season, scoringConfig });

      expect(presenter.getViewModel()).toEqual({
        leagueId: 'league-1',
        success: true,
      });
    });
  });

  describe('reset', () => {
    it('should reset the model and cause getViewModel to throw', () => {
      const league = League.create({
        id: 'league-1',
        name: 'Test League',
        description: 'A test league',
        ownerId: 'owner-1',
        settings: { pointsSystem: 'f1-2024' },
      });

      const season = Season.create({
        id: 'season-1',
        leagueId: 'league-1',
        gameId: 'iracing',
        name: 'Test League Season 1',
        status: 'active',
      } as never);

      const scoringConfig = LeagueScoringConfig.create({
        id: 'scoring-1',
        seasonId: 'season-1',
        scoringPresetId: 'preset-1',
        championships: [
          {
            id: 'champ-1',
            name: 'Driver Championship',
            type: 'driver',
            sessionTypes: ['main'],
            pointsTableBySessionType: {
              practice: new PointsTable({}),
              qualifying: new PointsTable({}),
              q1: new PointsTable({}),
              q2: new PointsTable({}),
              q3: new PointsTable({}),
              sprint: new PointsTable({}),
              main: new PointsTable({ 1: 25, 2: 18, 3: 15 }),
              timeTrial: new PointsTable({}),
            },
            dropScorePolicy: { strategy: 'none' },
          },
        ],
      });

      presenter.present({ league, season, scoringConfig });
      expect(presenter.getViewModel()).not.toBeNull();

      presenter.reset();

      expect(() => presenter.getViewModel()).toThrow('Presenter not presented');
    });
  });
});