import { describe, it, expect, vi } from 'vitest';

import { Season } from '@core/racing/domain/entities/season/Season';
import type { ISeasonRepository } from '@core/racing/domain/repositories/ISeasonRepository';
import type { ILeagueRepository } from '@core/racing/domain/repositories/ILeagueRepository';
import {
  CreateSeasonForLeagueUseCase,
  type CreateSeasonForLeagueCommand,
} from '@core/racing/application/use-cases/CreateSeasonForLeagueUseCase';
import type { LeagueConfigFormModel } from '@core/racing/application/dto/LeagueConfigFormDTO';

function createLeagueConfigFormModel(overrides?: Partial<LeagueConfigFormModel>): LeagueConfigFormModel {
  return {
    basics: {
      name: 'Test League',
      visibility: 'ranked',
      gameId: 'iracing',
      ...overrides?.basics,
    },
    structure: {
      mode: 'solo',
      maxDrivers: 30,
      ...overrides?.structure,
    },
    championships: {
      enableDriverChampionship: true,
      enableTeamChampionship: false,
      enableNationsChampionship: false,
      enableTrophyChampionship: false,
      ...overrides?.championships,
    },
    scoring: {
      patternId: 'sprint-main-driver',
      customScoringEnabled: false,
      ...overrides?.scoring,
    },
    dropPolicy: {
      strategy: 'bestNResults',
      n: 3,
      ...overrides?.dropPolicy,
    },
    timings: {
      qualifyingMinutes: 10,
      mainRaceMinutes: 30,
      sessionCount: 8,
      seasonStartDate: '2025-01-01',
      raceStartTime: '20:00',
      timezoneId: 'UTC',
      recurrenceStrategy: 'weekly',
      weekdays: ['Mon'],
      ...overrides?.timings,
    },
    stewarding: {
      decisionMode: 'steward_vote',
      requiredVotes: 3,
      requireDefense: true,
      defenseTimeLimit: 24,
      voteTimeLimit: 24,
      protestDeadlineHours: 48,
      stewardingClosesHours: 72,
      notifyAccusedOnProtest: true,
      notifyOnVoteRequired: true,
      ...overrides?.stewarding,
    },
    ...overrides,
  };
}

describe('CreateSeasonForLeagueUseCase', () => {
  const mockLeagueFindById = vi.fn();
  const mockLeagueRepo: ILeagueRepository = {
    findById: mockLeagueFindById,
    findAll: vi.fn(),
    findByOwnerId: vi.fn(),
    create: vi.fn(),
    update: vi.fn(),
    delete: vi.fn(),
    exists: vi.fn(),
    searchByName: vi.fn(),
  };

  const mockSeasonFindById = vi.fn();
  const mockSeasonAdd = vi.fn();
  const mockSeasonRepo: ISeasonRepository = {
    findById: mockSeasonFindById,
    findByLeagueId: vi.fn(),
    create: vi.fn(),
    add: mockSeasonAdd,
    update: vi.fn(),
    listByLeague: vi.fn(),
    listActiveByLeague: vi.fn(),
  };

  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('creates a planned Season for an existing league with config-derived props', async () => {
    mockLeagueFindById.mockResolvedValue({ id: 'league-1' });
    mockSeasonAdd.mockResolvedValue(undefined);

    const useCase = new CreateSeasonForLeagueUseCase(mockLeagueRepo, mockSeasonRepo);

    const config = createLeagueConfigFormModel({
      basics: {
        name: 'League With Config',
        visibility: 'ranked',
        gameId: 'iracing',
      },
      scoring: {
        patternId: 'club-default',
        customScoringEnabled: true,
      },
      dropPolicy: {
        strategy: 'dropWorstN',
        n: 2,
      },
      // Intentionally omit seasonStartDate / raceStartTime to avoid schedule derivation,
      // focusing this test on scoring/drop/stewarding/maxDrivers mapping.
      timings: {
        qualifyingMinutes: 10,
        mainRaceMinutes: 30,
        sessionCount: 8,
      },
    });

    const command: CreateSeasonForLeagueCommand = {
      leagueId: 'league-1',
      name: 'Season from Config',
      gameId: 'iracing',
      config,
    };

    const result = await useCase.execute(command);

    expect(result.isOk()).toBe(true);
    expect(result.value!.seasonId).toBeDefined();
  });

  it('clones configuration from a source season when sourceSeasonId is provided', async () => {
    const sourceSeason = Season.create({
      id: 'source-season',
      leagueId: 'league-1',
      gameId: 'iracing',
      name: 'Source Season',
      status: 'planned',
    }).withMaxDrivers(40);

    mockLeagueFindById.mockResolvedValue({ id: 'league-1' });
    mockSeasonFindById.mockResolvedValue(sourceSeason);
    mockSeasonAdd.mockResolvedValue(undefined);

    const useCase = new CreateSeasonForLeagueUseCase(mockLeagueRepo, mockSeasonRepo);

    const command: CreateSeasonForLeagueCommand = {
      leagueId: 'league-1',
      name: 'Cloned Season',
      gameId: 'iracing',
      sourceSeasonId: 'source-season',
    };

    const result = await useCase.execute(command);

    expect(result.isOk()).toBe(true);
    expect(result.value!.seasonId).toBeDefined();
  });
});