import { describe, it, expect } from 'vitest';
import { LeagueStandingsViewDataBuilder } from '../../../apps/website/lib/builders/view-data/LeagueStandingsViewDataBuilder';
import type { LeagueStandingDTO } from '../../../apps/website/lib/types/generated/LeagueStandingDTO';
import type { LeagueMemberDTO } from '../../../apps/website/lib/types/generated/LeagueMemberDTO';

describe('LeagueStandingsViewDataBuilder', () => {
  const mockStandings: LeagueStandingDTO[] = [
    {
      driverId: 'driver-1',
      driver: {
        id: 'driver-1',
        name: 'John Doe',
        iracingId: '12345',
        country: 'US',
        joinedAt: '2024-01-01T00:00:00Z',
      },
      points: 150,
      position: 1,
      wins: 3,
      podiums: 5,
      races: 10,
      positionChange: 0,
      lastRacePoints: 25,
      droppedRaceIds: ['race-1', 'race-2'],
    },
    {
      driverId: 'driver-2',
      driver: {
        id: 'driver-2',
        name: 'Jane Smith',
        iracingId: '67890',
        country: 'UK',
        joinedAt: '2024-01-02T00:00:00Z',
      },
      points: 120,
      position: 2,
      wins: 2,
      podiums: 4,
      races: 10,
      positionChange: 1,
      lastRacePoints: 18,
      droppedRaceIds: ['race-3'],
    },
    {
      driverId: 'driver-3',
      driver: {
        id: 'driver-3',
        name: 'Bob Wilson',
        iracingId: '11111',
        country: 'CA',
        joinedAt: '2024-01-03T00:00:00Z',
      },
      points: 90,
      position: 3,
      wins: 1,
      podiums: 3,
      races: 10,
      positionChange: -1,
      lastRacePoints: 12,
      droppedRaceIds: [],
    },
  ];

  const mockMemberships: LeagueMemberDTO[] = [
    {
      driverId: 'driver-1',
      driver: {
        id: 'driver-1',
        name: 'John Doe',
        iracingId: '12345',
        country: 'US',
        joinedAt: '2024-01-01T00:00:00Z',
      },
      role: 'member',
      joinedAt: '2024-01-01T00:00:00Z',
    },
    {
      driverId: 'driver-2',
      driver: {
        id: 'driver-2',
        name: 'Jane Smith',
        iracingId: '67890',
        country: 'UK',
        joinedAt: '2024-01-02T00:00:00Z',
      },
      role: 'member',
      joinedAt: '2024-01-02T00:00:00Z',
    },
  ];

  describe('build()', () => {
    it('should transform standings correctly', () => {
      const result = LeagueStandingsViewDataBuilder.build(
        { standings: mockStandings },
        { members: mockMemberships },
        'league-123'
      );

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

      // Check first standing
      expect(result.standings[0].driverId).toBe('driver-1');
      expect(result.standings[0].position).toBe(1);
      expect(result.standings[0].totalPoints).toBe(150);
      expect(result.standings[0].racesFinished).toBe(10);
      expect(result.standings[0].racesStarted).toBe(10);
      expect(result.standings[0].positionChange).toBe(0);
      expect(result.standings[0].lastRacePoints).toBe(25);
      expect(result.standings[0].droppedRaceIds).toEqual(['race-1', 'race-2']);
      expect(result.standings[0].wins).toBe(3);
      expect(result.standings[0].podiums).toBe(5);
    });

    it('should calculate position change correctly', () => {
      const result = LeagueStandingsViewDataBuilder.build(
        { standings: mockStandings },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.standings[0].positionChange).toBe(0); // No change
      expect(result.standings[1].positionChange).toBe(1); // Moved up
      expect(result.standings[2].positionChange).toBe(-1); // Moved down
    });

    it('should map last race points correctly', () => {
      const result = LeagueStandingsViewDataBuilder.build(
        { standings: mockStandings },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.standings[0].lastRacePoints).toBe(25);
      expect(result.standings[1].lastRacePoints).toBe(18);
      expect(result.standings[2].lastRacePoints).toBe(12);
    });

    it('should handle dropped race IDs correctly', () => {
      const result = LeagueStandingsViewDataBuilder.build(
        { standings: mockStandings },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.standings[0].droppedRaceIds).toEqual(['race-1', 'race-2']);
      expect(result.standings[1].droppedRaceIds).toEqual(['race-3']);
      expect(result.standings[2].droppedRaceIds).toEqual([]);
    });

    it('should calculate championship stats (wins, podiums)', () => {
      const result = LeagueStandingsViewDataBuilder.build(
        { standings: mockStandings },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.standings[0].wins).toBe(3);
      expect(result.standings[0].podiums).toBe(5);
      expect(result.standings[1].wins).toBe(2);
      expect(result.standings[1].podiums).toBe(4);
      expect(result.standings[2].wins).toBe(1);
      expect(result.standings[2].podiums).toBe(3);
    });

    it('should extract driver metadata correctly', () => {
      const result = LeagueStandingsViewDataBuilder.build(
        { standings: mockStandings },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.drivers).toHaveLength(3);

      // Check first driver
      expect(result.drivers[0].id).toBe('driver-1');
      expect(result.drivers[0].name).toBe('John Doe');
      expect(result.drivers[0].iracingId).toBe('12345');
      expect(result.drivers[0].country).toBe('US');
    });

    it('should convert memberships correctly', () => {
      const result = LeagueStandingsViewDataBuilder.build(
        { standings: mockStandings },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.memberships).toHaveLength(2);

      // Check first membership
      expect(result.memberships[0].driverId).toBe('driver-1');
      expect(result.memberships[0].leagueId).toBe('league-123');
      expect(result.memberships[0].role).toBe('member');
      expect(result.memberships[0].status).toBe('active');
    });

    it('should handle empty standings', () => {
      const result = LeagueStandingsViewDataBuilder.build(
        { standings: [] },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.standings).toHaveLength(0);
      expect(result.drivers).toHaveLength(0);
    });

    it('should handle empty memberships', () => {
      const result = LeagueStandingsViewDataBuilder.build(
        { standings: mockStandings },
        { members: [] },
        'league-123'
      );

      expect(result.memberships).toHaveLength(0);
    });

    it('should handle missing driver objects in standings', () => {
      const standingsWithMissingDriver: LeagueStandingDTO[] = [
        {
          driverId: 'driver-1',
          driver: {
            id: 'driver-1',
            name: 'John Doe',
            iracingId: '12345',
            country: 'US',
            joinedAt: '2024-01-01T00:00:00Z',
          },
          points: 150,
          position: 1,
          wins: 3,
          podiums: 5,
          races: 10,
          positionChange: 0,
          lastRacePoints: 25,
          droppedRaceIds: [],
        },
        {
          driverId: 'driver-2',
          driver: {
            id: 'driver-2',
            name: 'Jane Smith',
            iracingId: '67890',
            country: 'UK',
            joinedAt: '2024-01-02T00:00:00Z',
          },
          points: 120,
          position: 2,
          wins: 2,
          podiums: 4,
          races: 10,
          positionChange: 1,
          lastRacePoints: 18,
          droppedRaceIds: [],
        },
      ];

      const result = LeagueStandingsViewDataBuilder.build(
        { standings: standingsWithMissingDriver },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.drivers).toHaveLength(2);
      expect(result.drivers[0].id).toBe('driver-1');
      expect(result.drivers[1].id).toBe('driver-2');
    });

    it('should handle standings with missing positionChange', () => {
      const standingsWithoutPositionChange: LeagueStandingDTO[] = [
        {
          driverId: 'driver-1',
          driver: {
            id: 'driver-1',
            name: 'John Doe',
            iracingId: '12345',
            country: 'US',
            joinedAt: '2024-01-01T00:00:00Z',
          },
          points: 150,
          position: 1,
          wins: 3,
          podiums: 5,
          races: 10,
          positionChange: undefined as any,
          lastRacePoints: 25,
          droppedRaceIds: [],
        },
      ];

      const result = LeagueStandingsViewDataBuilder.build(
        { standings: standingsWithoutPositionChange },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.standings[0].positionChange).toBe(0);
    });

    it('should handle standings with missing lastRacePoints', () => {
      const standingsWithoutLastRacePoints: LeagueStandingDTO[] = [
        {
          driverId: 'driver-1',
          driver: {
            id: 'driver-1',
            name: 'John Doe',
            iracingId: '12345',
            country: 'US',
            joinedAt: '2024-01-01T00:00:00Z',
          },
          points: 150,
          position: 1,
          wins: 3,
          podiums: 5,
          races: 10,
          positionChange: 0,
          lastRacePoints: undefined as any,
          droppedRaceIds: [],
        },
      ];

      const result = LeagueStandingsViewDataBuilder.build(
        { standings: standingsWithoutLastRacePoints },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.standings[0].lastRacePoints).toBe(0);
    });

    it('should handle standings with missing droppedRaceIds', () => {
      const standingsWithoutDroppedRaceIds: LeagueStandingDTO[] = [
        {
          driverId: 'driver-1',
          driver: {
            id: 'driver-1',
            name: 'John Doe',
            iracingId: '12345',
            country: 'US',
            joinedAt: '2024-01-01T00:00:00Z',
          },
          points: 150,
          position: 1,
          wins: 3,
          podiums: 5,
          races: 10,
          positionChange: 0,
          lastRacePoints: 25,
          droppedRaceIds: undefined as any,
        },
      ];

      const result = LeagueStandingsViewDataBuilder.build(
        { standings: standingsWithoutDroppedRaceIds },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.standings[0].droppedRaceIds).toEqual([]);
    });

    it('should handle standings with missing wins', () => {
      const standingsWithoutWins: LeagueStandingDTO[] = [
        {
          driverId: 'driver-1',
          driver: {
            id: 'driver-1',
            name: 'John Doe',
            iracingId: '12345',
            country: 'US',
            joinedAt: '2024-01-01T00:00:00Z',
          },
          points: 150,
          position: 1,
          wins: undefined as any,
          podiums: 5,
          races: 10,
          positionChange: 0,
          lastRacePoints: 25,
          droppedRaceIds: [],
        },
      ];

      const result = LeagueStandingsViewDataBuilder.build(
        { standings: standingsWithoutWins },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.standings[0].wins).toBe(0);
    });

    it('should handle standings with missing podiums', () => {
      const standingsWithoutPodiums: LeagueStandingDTO[] = [
        {
          driverId: 'driver-1',
          driver: {
            id: 'driver-1',
            name: 'John Doe',
            iracingId: '12345',
            country: 'US',
            joinedAt: '2024-01-01T00:00:00Z',
          },
          points: 150,
          position: 1,
          wins: 3,
          podiums: undefined as any,
          races: 10,
          positionChange: 0,
          lastRacePoints: 25,
          droppedRaceIds: [],
        },
      ];

      const result = LeagueStandingsViewDataBuilder.build(
        { standings: standingsWithoutPodiums },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.standings[0].podiums).toBe(0);
    });

    it('should handle team championship mode', () => {
      const result = LeagueStandingsViewDataBuilder.build(
        { standings: mockStandings },
        { members: mockMemberships },
        'league-123',
        true
      );

      expect(result.isTeamChampionship).toBe(true);
    });

    it('should handle non-team championship mode by default', () => {
      const result = LeagueStandingsViewDataBuilder.build(
        { standings: mockStandings },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.isTeamChampionship).toBe(false);
    });

    it('should handle standings with zero points', () => {
      const standingsWithZeroPoints: LeagueStandingDTO[] = [
        {
          driverId: 'driver-1',
          driver: {
            id: 'driver-1',
            name: 'John Doe',
            iracingId: '12345',
            country: 'US',
            joinedAt: '2024-01-01T00:00:00Z',
          },
          points: 0,
          position: 1,
          wins: 0,
          podiums: 0,
          races: 10,
          positionChange: 0,
          lastRacePoints: 0,
          droppedRaceIds: [],
        },
      ];

      const result = LeagueStandingsViewDataBuilder.build(
        { standings: standingsWithZeroPoints },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.standings[0].totalPoints).toBe(0);
      expect(result.standings[0].wins).toBe(0);
      expect(result.standings[0].podiums).toBe(0);
    });

    it('should handle standings with negative position change', () => {
      const standingsWithNegativeChange: LeagueStandingDTO[] = [
        {
          driverId: 'driver-1',
          driver: {
            id: 'driver-1',
            name: 'John Doe',
            iracingId: '12345',
            country: 'US',
            joinedAt: '2024-01-01T00:00:00Z',
          },
          points: 150,
          position: 1,
          wins: 3,
          podiums: 5,
          races: 10,
          positionChange: -2,
          lastRacePoints: 25,
          droppedRaceIds: [],
        },
      ];

      const result = LeagueStandingsViewDataBuilder.build(
        { standings: standingsWithNegativeChange },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.standings[0].positionChange).toBe(-2);
    });

    it('should handle standings with positive position change', () => {
      const standingsWithPositiveChange: LeagueStandingDTO[] = [
        {
          driverId: 'driver-1',
          driver: {
            id: 'driver-1',
            name: 'John Doe',
            iracingId: '12345',
            country: 'US',
            joinedAt: '2024-01-01T00:00:00Z',
          },
          points: 150,
          position: 1,
          wins: 3,
          podiums: 5,
          races: 10,
          positionChange: 3,
          lastRacePoints: 25,
          droppedRaceIds: [],
        },
      ];

      const result = LeagueStandingsViewDataBuilder.build(
        { standings: standingsWithPositiveChange },
        { members: mockMemberships },
        'league-123'
      );

      expect(result.standings[0].positionChange).toBe(3);
    });
  });
});
