import { describe, expect, it, vi } from 'vitest';
import { LeagueController } from './LeagueController';
import { LeagueService } from './LeagueService';

describe('LeagueController - Detail Endpoints', () => {
  let controller: LeagueController;
  let mockService: ReturnType<typeof vi.mocked<LeagueService>>;

  beforeEach(() => {
    mockService = {
      getLeagueOwnerSummary: vi.fn(),
      getLeagueSeasons: vi.fn(),
      getLeagueStats: vi.fn(),
      getLeagueMemberships: vi.fn(),
    } as never;

    controller = new LeagueController(mockService);
  });

  describe('getLeague', () => {
    it('should return league details by ID', async () => {
      const mockResult = {
        driver: {
          id: 'driver-1',
          iracingId: '12345',
          name: 'John Doe',
          country: 'US',
          joinedAt: '2024-01-01T00:00:00Z',
        },
        rating: 1500,
        rank: 10,
      };
      mockService.getLeagueOwnerSummary.mockResolvedValue(mockResult as never);

      const result = await controller.getLeague('league-1');

      expect(result).toEqual(mockResult);
      expect(mockService.getLeagueOwnerSummary).toHaveBeenCalledWith({
        ownerId: 'unknown',
        leagueId: 'league-1',
      });
    });

    it('should handle league not found gracefully', async () => {
      mockService.getLeagueOwnerSummary.mockRejectedValue(new Error('League not found'));

      await expect(controller.getLeague('non-existent-league')).rejects.toThrow('League not found');
    });

    it('should return league with minimal information', async () => {
      const mockResult = {
        driver: {
          id: 'driver-1',
          iracingId: '12345',
          name: 'Simple Driver',
          country: 'DE',
          joinedAt: '2024-01-01T00:00:00Z',
        },
        rating: null,
        rank: null,
      };
      mockService.getLeagueOwnerSummary.mockResolvedValue(mockResult as never);

      const result = await controller.getLeague('league-1');

      expect(result).toEqual(mockResult);
      expect(result.driver.name).toBe('Simple Driver');
      expect(result.rating).toBeNull();
    });
  });

  describe('getLeagueSeasons', () => {
    it('should return seasons for a league', async () => {
      const mockResult = [
        {
          seasonId: 'season-1',
          name: 'Season 1',
          status: 'active',
          startDate: new Date('2024-01-01'),
          endDate: new Date('2024-06-30'),
          isPrimary: true,
          isParallelActive: false,
          totalRaces: 12,
          completedRaces: 6,
          nextRaceAt: new Date('2024-03-15'),
        },
        {
          seasonId: 'season-2',
          name: 'Season 2',
          status: 'upcoming',
          startDate: new Date('2024-07-01'),
          endDate: new Date('2024-12-31'),
          isPrimary: false,
          isParallelActive: false,
          totalRaces: 12,
          completedRaces: 0,
        },
      ];
      mockService.getLeagueSeasons.mockResolvedValue(mockResult as never);

      const result = await controller.getLeagueSeasons('league-1');

      expect(result).toEqual(mockResult);
      expect(mockService.getLeagueSeasons).toHaveBeenCalledWith({ leagueId: 'league-1' });
    });

    it('should return empty array when league has no seasons', async () => {
      const mockResult: never[] = [];
      mockService.getLeagueSeasons.mockResolvedValue(mockResult);

      const result = await controller.getLeagueSeasons('league-1');

      expect(result).toEqual([]);
      expect(result).toHaveLength(0);
    });

    it('should handle league with single season', async () => {
      const mockResult = [
        {
          seasonId: 'season-1',
          name: 'Season 1',
          status: 'active',
          startDate: new Date('2024-01-01'),
          endDate: new Date('2024-12-31'),
          isPrimary: true,
          isParallelActive: false,
          totalRaces: 24,
          completedRaces: 12,
          nextRaceAt: new Date('2024-06-15'),
        },
      ];
      mockService.getLeagueSeasons.mockResolvedValue(mockResult as never);

      const result = await controller.getLeagueSeasons('league-1');

      expect(result).toEqual(mockResult);
      expect(result).toHaveLength(1);
      expect(result[0]?.totalRaces).toBe(24);
    });

    it('should handle seasons with different statuses', async () => {
      const mockResult = [
        {
          seasonId: 'season-1',
          name: 'Season 1',
          status: 'completed',
          startDate: new Date('2024-01-01'),
          endDate: new Date('2024-06-30'),
          isPrimary: true,
          isParallelActive: false,
          totalRaces: 12,
          completedRaces: 12,
        },
        {
          seasonId: 'season-2',
          name: 'Season 2',
          status: 'active',
          startDate: new Date('2024-07-01'),
          endDate: new Date('2024-12-31'),
          isPrimary: false,
          isParallelActive: false,
          totalRaces: 12,
          completedRaces: 6,
          nextRaceAt: new Date('2024-10-15'),
        },
        {
          seasonId: 'season-3',
          name: 'Season 3',
          status: 'upcoming',
          startDate: new Date('2025-01-01'),
          endDate: new Date('2025-06-30'),
          isPrimary: false,
          isParallelActive: false,
          totalRaces: 12,
          completedRaces: 0,
        },
      ];
      mockService.getLeagueSeasons.mockResolvedValue(mockResult as never);

      const result = await controller.getLeagueSeasons('league-1');

      expect(result).toEqual(mockResult);
      expect(result).toHaveLength(3);
      expect(result[0]?.status).toBe('completed');
      expect(result[1]?.status).toBe('active');
      expect(result[2]?.status).toBe('upcoming');
    });
  });

  describe('getLeagueStats', () => {
    it('should return league statistics', async () => {
      const mockResult = {
        totalMembers: 25,
        totalRaces: 150,
        averageRating: 1450.5,
      };
      mockService.getLeagueStats.mockResolvedValue(mockResult as never);

      const result = await controller.getLeagueStats('league-1');

      expect(result).toEqual(mockResult);
      expect(mockService.getLeagueStats).toHaveBeenCalledWith('league-1');
    });

    it('should return empty stats for new league', async () => {
      const mockResult = {
        totalMembers: 0,
        totalRaces: 0,
        averageRating: 0,
      };
      mockService.getLeagueStats.mockResolvedValue(mockResult as never);

      const result = await controller.getLeagueStats('league-1');

      expect(result).toEqual(mockResult);
      expect(result.totalMembers).toBe(0);
      expect(result.totalRaces).toBe(0);
    });

    it('should handle league with extensive statistics', async () => {
      const mockResult = {
        totalMembers: 100,
        totalRaces: 500,
        averageRating: 1650.75,
      };
      mockService.getLeagueStats.mockResolvedValue(mockResult as never);

      const result = await controller.getLeagueStats('league-1');

      expect(result).toEqual(mockResult);
      expect(result.totalRaces).toBe(500);
      expect(result.totalMembers).toBe(100);
    });
  });

  describe('getLeagueMemberships', () => {
    it('should return league memberships', async () => {
      const mockResult = {
        members: [
          {
            driverId: 'driver-1',
            driver: {
              id: 'driver-1',
              iracingId: '12345',
              name: 'John Doe',
              country: 'US',
              joinedAt: '2024-01-01T00:00:00Z',
            },
            role: 'owner',
            joinedAt: '2024-01-01T00:00:00Z',
          },
          {
            driverId: 'driver-2',
            driver: {
              id: 'driver-2',
              iracingId: '67890',
              name: 'Jane Smith',
              country: 'UK',
              joinedAt: '2024-01-15T00:00:00Z',
            },
            role: 'admin',
            joinedAt: '2024-01-15T00:00:00Z',
          },
          {
            driverId: 'driver-3',
            driver: {
              id: 'driver-3',
              iracingId: '11111',
              name: 'Bob Johnson',
              country: 'CA',
              joinedAt: '2024-02-01T00:00:00Z',
            },
            role: 'member',
            joinedAt: '2024-02-01T00:00:00Z',
          },
        ],
      };
      mockService.getLeagueMemberships.mockResolvedValue(mockResult as never);

      const result = await controller.getLeagueMemberships('league-1');

      expect(result).toEqual(mockResult);
      expect(mockService.getLeagueMemberships).toHaveBeenCalledWith('league-1');
    });

    it('should return empty memberships for league with no members', async () => {
      const mockResult = { members: [] };
      mockService.getLeagueMemberships.mockResolvedValue(mockResult as never);

      const result = await controller.getLeagueMemberships('league-1');

      expect(result).toEqual(mockResult);
      expect(result.members).toHaveLength(0);
    });

    it('should handle league with only owner', async () => {
      const mockResult = {
        members: [
          {
            driverId: 'driver-1',
            driver: {
              id: 'driver-1',
              iracingId: '12345',
              name: 'Owner',
              country: 'US',
              joinedAt: '2024-01-01T00:00:00Z',
            },
            role: 'owner',
            joinedAt: '2024-01-01T00:00:00Z',
          },
        ],
      };
      mockService.getLeagueMemberships.mockResolvedValue(mockResult as never);

      const result = await controller.getLeagueMemberships('league-1');

      expect(result).toEqual(mockResult);
      expect(result.members).toHaveLength(1);
      expect(result.members[0]?.role).toBe('owner');
    });

    it('should handle league with mixed roles', async () => {
      const mockResult = {
        members: [
          {
            driverId: 'driver-1',
            driver: {
              id: 'driver-1',
              iracingId: '12345',
              name: 'Owner',
              country: 'US',
              joinedAt: '2024-01-01T00:00:00Z',
            },
            role: 'owner',
            joinedAt: '2024-01-01T00:00:00Z',
          },
          {
            driverId: 'driver-2',
            driver: {
              id: 'driver-2',
              iracingId: '67890',
              name: 'Admin 1',
              country: 'UK',
              joinedAt: '2024-01-02T00:00:00Z',
            },
            role: 'admin',
            joinedAt: '2024-01-02T00:00:00Z',
          },
          {
            driverId: 'driver-3',
            driver: {
              id: 'driver-3',
              iracingId: '11111',
              name: 'Admin 2',
              country: 'CA',
              joinedAt: '2024-01-03T00:00:00Z',
            },
            role: 'admin',
            joinedAt: '2024-01-03T00:00:00Z',
          },
          {
            driverId: 'driver-4',
            driver: {
              id: 'driver-4',
              iracingId: '22222',
              name: 'Member 1',
              country: 'DE',
              joinedAt: '2024-01-04T00:00:00Z',
            },
            role: 'member',
            joinedAt: '2024-01-04T00:00:00Z',
          },
          {
            driverId: 'driver-5',
            driver: {
              id: 'driver-5',
              iracingId: '33333',
              name: 'Member 2',
              country: 'FR',
              joinedAt: '2024-01-05T00:00:00Z',
            },
            role: 'member',
            joinedAt: '2024-01-05T00:00:00Z',
          },
        ],
      };
      mockService.getLeagueMemberships.mockResolvedValue(mockResult as never);

      const result = await controller.getLeagueMemberships('league-1');

      expect(result).toEqual(mockResult);
      expect(result.members).toHaveLength(5);
      expect(result.members.filter(m => m.role === 'owner')).toHaveLength(1);
      expect(result.members.filter(m => m.role === 'admin')).toHaveLength(2);
      expect(result.members.filter(m => m.role === 'member')).toHaveLength(2);
    });
  });
});
