import { describe, it, expect } from 'vitest';
import { LeagueScheduleViewDataBuilder } from '../../../apps/website/lib/builders/view-data/LeagueScheduleViewDataBuilder';
import type { LeagueScheduleApiDto } from '../../../apps/website/lib/types/tbd/LeagueScheduleApiDto';

describe('LeagueScheduleViewDataBuilder', () => {
  const mockApiDto: LeagueScheduleApiDto = {
    leagueId: 'league-123',
    races: [
      {
        id: 'race-1',
        name: 'Race 1',
        date: '2024-02-01T18:00:00Z',
        track: 'Track A',
        car: 'Car A',
        sessionType: 'Qualifying',
      },
      {
        id: 'race-2',
        name: 'Race 2',
        date: '2024-02-08T18:00:00Z',
        track: 'Track B',
        car: 'Car B',
        sessionType: 'Race',
      },
      {
        id: 'race-3',
        name: 'Race 3',
        date: '2024-02-15T18:00:00Z',
        track: 'Track C',
        car: 'Car C',
        sessionType: 'Race',
      },
    ],
  };

  describe('build()', () => {
    it('should transform all races correctly', () => {
      const result = LeagueScheduleViewDataBuilder.build(mockApiDto);

      expect(result.leagueId).toBe('league-123');
      expect(result.races).toHaveLength(3);

      // Check first race
      expect(result.races[0].id).toBe('race-1');
      expect(result.races[0].name).toBe('Race 1');
      expect(result.races[0].scheduledAt).toBe('2024-02-01T18:00:00Z');
      expect(result.races[0].track).toBe('Track A');
      expect(result.races[0].car).toBe('Car A');
      expect(result.races[0].sessionType).toBe('Qualifying');
    });

    it('should mark past races correctly', () => {
      const now = new Date();
      const pastDate = new Date(now.getTime() - 86400000).toISOString(); // 1 day ago
      const futureDate = new Date(now.getTime() + 86400000).toISOString(); // 1 day from now

      const apiDto: LeagueScheduleApiDto = {
        leagueId: 'league-123',
        races: [
          {
            id: 'race-past',
            name: 'Past Race',
            date: pastDate,
            track: 'Track A',
            car: 'Car A',
            sessionType: 'Race',
          },
          {
            id: 'race-future',
            name: 'Future Race',
            date: futureDate,
            track: 'Track B',
            car: 'Car B',
            sessionType: 'Race',
          },
        ],
      };

      const result = LeagueScheduleViewDataBuilder.build(apiDto);

      expect(result.races[0].isPast).toBe(true);
      expect(result.races[0].isUpcoming).toBe(false);
      expect(result.races[0].status).toBe('completed');

      expect(result.races[1].isPast).toBe(false);
      expect(result.races[1].isUpcoming).toBe(true);
      expect(result.races[1].status).toBe('scheduled');
    });

    it('should mark upcoming races correctly', () => {
      const now = new Date();
      const futureDate = new Date(now.getTime() + 86400000).toISOString(); // 1 day from now

      const apiDto: LeagueScheduleApiDto = {
        leagueId: 'league-123',
        races: [
          {
            id: 'race-future',
            name: 'Future Race',
            date: futureDate,
            track: 'Track A',
            car: 'Car A',
            sessionType: 'Race',
          },
        ],
      };

      const result = LeagueScheduleViewDataBuilder.build(apiDto);

      expect(result.races[0].isPast).toBe(false);
      expect(result.races[0].isUpcoming).toBe(true);
      expect(result.races[0].status).toBe('scheduled');
    });

    it('should handle empty schedule', () => {
      const apiDto: LeagueScheduleApiDto = {
        leagueId: 'league-123',
        races: [],
      };

      const result = LeagueScheduleViewDataBuilder.build(apiDto);

      expect(result.leagueId).toBe('league-123');
      expect(result.races).toHaveLength(0);
    });

    it('should handle races with missing optional fields', () => {
      const apiDto: LeagueScheduleApiDto = {
        leagueId: 'league-123',
        races: [
          {
            id: 'race-1',
            name: 'Race 1',
            date: '2024-02-01T18:00:00Z',
            track: undefined,
            car: undefined,
            sessionType: undefined,
          },
        ],
      };

      const result = LeagueScheduleViewDataBuilder.build(apiDto);

      expect(result.races[0].track).toBeUndefined();
      expect(result.races[0].car).toBeUndefined();
      expect(result.races[0].sessionType).toBeUndefined();
    });

    it('should handle current driver ID parameter', () => {
      const result = LeagueScheduleViewDataBuilder.build(mockApiDto, 'driver-456');

      expect(result.currentDriverId).toBe('driver-456');
    });

    it('should handle admin permission parameter', () => {
      const result = LeagueScheduleViewDataBuilder.build(mockApiDto, 'driver-456', true);

      expect(result.isAdmin).toBe(true);
      expect(result.races[0].canEdit).toBe(true);
      expect(result.races[0].canReschedule).toBe(true);
    });

    it('should handle non-admin permission parameter', () => {
      const result = LeagueScheduleViewDataBuilder.build(mockApiDto, 'driver-456', false);

      expect(result.isAdmin).toBe(false);
      expect(result.races[0].canEdit).toBe(false);
      expect(result.races[0].canReschedule).toBe(false);
    });

    it('should handle default admin parameter as false', () => {
      const result = LeagueScheduleViewDataBuilder.build(mockApiDto, 'driver-456');

      expect(result.isAdmin).toBe(false);
      expect(result.races[0].canEdit).toBe(false);
      expect(result.races[0].canReschedule).toBe(false);
    });

    it('should handle registration status for upcoming races', () => {
      const now = new Date();
      const futureDate = new Date(now.getTime() + 86400000).toISOString();

      const apiDto: LeagueScheduleApiDto = {
        leagueId: 'league-123',
        races: [
          {
            id: 'race-future',
            name: 'Future Race',
            date: futureDate,
            track: 'Track A',
            car: 'Car A',
            sessionType: 'Race',
          },
        ],
      };

      const result = LeagueScheduleViewDataBuilder.build(apiDto);

      expect(result.races[0].isUserRegistered).toBe(false);
      expect(result.races[0].canRegister).toBe(true);
    });

    it('should handle registration status for past races', () => {
      const now = new Date();
      const pastDate = new Date(now.getTime() - 86400000).toISOString();

      const apiDto: LeagueScheduleApiDto = {
        leagueId: 'league-123',
        races: [
          {
            id: 'race-past',
            name: 'Past Race',
            date: pastDate,
            track: 'Track A',
            car: 'Car A',
            sessionType: 'Race',
          },
        ],
      };

      const result = LeagueScheduleViewDataBuilder.build(apiDto);

      expect(result.races[0].isUserRegistered).toBe(false);
      expect(result.races[0].canRegister).toBe(false);
    });

    it('should handle races exactly at current time', () => {
      const now = new Date();
      const exactDate = now.toISOString();

      const apiDto: LeagueScheduleApiDto = {
        leagueId: 'league-123',
        races: [
          {
            id: 'race-exact',
            name: 'Exact Race',
            date: exactDate,
            track: 'Track A',
            car: 'Car A',
            sessionType: 'Race',
          },
        ],
      };

      const result = LeagueScheduleViewDataBuilder.build(apiDto);

      // Race at exact current time is considered upcoming (not past)
      // because the comparison uses < (strictly less than)
      expect(result.races[0].isPast).toBe(false);
      expect(result.races[0].isUpcoming).toBe(true);
      expect(result.races[0].status).toBe('scheduled');
    });

    it('should handle races with different session types', () => {
      const apiDto: LeagueScheduleApiDto = {
        leagueId: 'league-123',
        races: [
          {
            id: 'race-qualifying',
            name: 'Qualifying',
            date: '2024-02-01T18:00:00Z',
            track: 'Track A',
            car: 'Car A',
            sessionType: 'Qualifying',
          },
          {
            id: 'race-practice',
            name: 'Practice',
            date: '2024-02-02T18:00:00Z',
            track: 'Track B',
            car: 'Car B',
            sessionType: 'Practice',
          },
          {
            id: 'race-race',
            name: 'Race',
            date: '2024-02-03T18:00:00Z',
            track: 'Track C',
            car: 'Car C',
            sessionType: 'Race',
          },
        ],
      };

      const result = LeagueScheduleViewDataBuilder.build(apiDto);

      expect(result.races[0].sessionType).toBe('Qualifying');
      expect(result.races[1].sessionType).toBe('Practice');
      expect(result.races[2].sessionType).toBe('Race');
    });

    it('should handle races without session type', () => {
      const apiDto: LeagueScheduleApiDto = {
        leagueId: 'league-123',
        races: [
          {
            id: 'race-1',
            name: 'Race 1',
            date: '2024-02-01T18:00:00Z',
            track: 'Track A',
            car: 'Car A',
          },
        ],
      };

      const result = LeagueScheduleViewDataBuilder.build(apiDto);

      expect(result.races[0].sessionType).toBeUndefined();
    });

    it('should handle races with empty track and car', () => {
      const apiDto: LeagueScheduleApiDto = {
        leagueId: 'league-123',
        races: [
          {
            id: 'race-1',
            name: 'Race 1',
            date: '2024-02-01T18:00:00Z',
            track: '',
            car: '',
            sessionType: 'Race',
          },
        ],
      };

      const result = LeagueScheduleViewDataBuilder.build(apiDto);

      expect(result.races[0].track).toBe('');
      expect(result.races[0].car).toBe('');
    });

    it('should handle multiple races with mixed dates', () => {
      const now = new Date();
      const pastDate1 = new Date(now.getTime() - 172800000).toISOString(); // 2 days ago
      const pastDate2 = new Date(now.getTime() - 86400000).toISOString(); // 1 day ago
      const futureDate1 = new Date(now.getTime() + 86400000).toISOString(); // 1 day from now
      const futureDate2 = new Date(now.getTime() + 172800000).toISOString(); // 2 days from now

      const apiDto: LeagueScheduleApiDto = {
        leagueId: 'league-123',
        races: [
          {
            id: 'race-past-2',
            name: 'Past Race 2',
            date: pastDate1,
            track: 'Track A',
            car: 'Car A',
            sessionType: 'Race',
          },
          {
            id: 'race-past-1',
            name: 'Past Race 1',
            date: pastDate2,
            track: 'Track B',
            car: 'Car B',
            sessionType: 'Race',
          },
          {
            id: 'race-future-1',
            name: 'Future Race 1',
            date: futureDate1,
            track: 'Track C',
            car: 'Car C',
            sessionType: 'Race',
          },
          {
            id: 'race-future-2',
            name: 'Future Race 2',
            date: futureDate2,
            track: 'Track D',
            car: 'Car D',
            sessionType: 'Race',
          },
        ],
      };

      const result = LeagueScheduleViewDataBuilder.build(apiDto);

      expect(result.races).toHaveLength(4);
      expect(result.races[0].isPast).toBe(true);
      expect(result.races[1].isPast).toBe(true);
      expect(result.races[2].isPast).toBe(false);
      expect(result.races[3].isPast).toBe(false);
    });
  });
});
