/**
 * Integration Tests for LeagueDetailPageQuery
 *
 * Tests the LeagueDetailPageQuery with mocked API clients to verify:
 * - Happy path: API returns valid league detail data
 * - Error handling: 404 when league not found
 * - Error handling: 500 when API server error
 * - Missing data: API returns partial data
 */

import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { LeagueDetailPageQuery } from '@/lib/page-queries/LeagueDetailPageQuery';
import { MockLeaguesApiClient } from './mocks/MockLeaguesApiClient';
import { ApiError } from '../../../apps/website/lib/api/base/ApiError';

// Mock data factories
const createMockLeagueDetailData = () => ({
  leagues: [
    {
      id: 'league-1',
      name: 'Test League',
      description: 'A test league',
      capacity: 10,
      currentMembers: 5,
      ownerId: 'driver-1',
      status: 'active' as const,
      createdAt: new Date().toISOString(),
      updatedAt: new Date().toISOString(),
    },
  ],
});

const createMockMembershipsData = () => ({
  members: [
    {
      driverId: 'driver-1',
      driver: {
        id: 'driver-1',
        iracingId: '12345',
        name: 'Test Driver',
        country: 'US',
        joinedAt: new Date().toISOString(),
      },
      role: 'owner' as const,
      status: 'active' as const,
      joinedAt: new Date().toISOString(),
    },
  ],
});

const createMockRacesPageData = () => ({
  races: [
    {
      id: 'race-1',
      track: 'Test Track',
      car: 'Test Car',
      scheduledAt: new Date().toISOString(),
      leagueName: 'Test League',
      status: 'scheduled' as const,
      strengthOfField: 50,
    },
  ],
});

const createMockDriverData = () => ({
  id: 'driver-1',
  iracingId: '12345',
  name: 'Test Driver',
  country: 'US',
  joinedAt: new Date().toISOString(),
});

const createMockLeagueConfigData = () => ({
  form: {
    scoring: {
      presetId: 'preset-1',
    },
  },
});

describe('LeagueDetailPageQuery Integration', () => {
  let mockLeaguesApiClient: MockLeaguesApiClient;

  beforeEach(() => {
    mockLeaguesApiClient = new MockLeaguesApiClient();
  });

  afterEach(() => {
    mockLeaguesApiClient.clearMocks();
  });

  describe('Happy Path', () => {
    it('should return valid league detail data when API returns success', async () => {
      // Arrange
      const leagueId = 'league-1';
      const mockLeaguesData = createMockLeagueDetailData();
      const mockMembershipsData = createMockMembershipsData();
      const mockRacesPageData = createMockRacesPageData();
      const mockDriverData = createMockDriverData();
      const mockLeagueConfigData = createMockLeagueConfigData();

      // Mock fetch to return different data based on the URL
      global.fetch = vi.fn((url: string) => {
        if (url.includes('/leagues/all-with-capacity-and-scoring')) {
          return Promise.resolve(createMockResponse(mockLeaguesData));
        }
        if (url.includes('/memberships')) {
          return Promise.resolve(createMockResponse(mockMembershipsData));
        }
        if (url.includes('/races/page-data')) {
          return Promise.resolve(createMockResponse(mockRacesPageData));
        }
        if (url.includes('/drivers/driver-1')) {
          return Promise.resolve(createMockResponse(mockDriverData));
        }
        if (url.includes('/config')) {
          return Promise.resolve(createMockResponse(mockLeagueConfigData));
        }
        return Promise.resolve(createMockErrorResponse(404, 'Not Found', 'Not Found'));
      });
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isOk()).toBe(true);
      const data = result.unwrap();
      
      expect(data).toBeDefined();
      expect(data.league).toBeDefined();
      expect(data.league.id).toBe('league-1');
      expect(data.league.name).toBe('Test League');
      expect(data.league.capacity).toBe(10);
      expect(data.league.currentMembers).toBe(5);
      
      expect(data.owner).toBeDefined();
      expect(data.owner?.id).toBe('driver-1');
      expect(data.owner?.name).toBe('Test Driver');
      
      expect(data.memberships).toBeDefined();
      expect(data.memberships.members).toBeDefined();
      expect(data.memberships.members.length).toBe(1);
      
      expect(data.races).toBeDefined();
      expect(data.races.length).toBe(1);
      expect(data.races[0].id).toBe('race-1');
      expect(data.races[0].name).toBe('Test Track - Test Car');
      
      expect(data.scoringConfig).toBeDefined();
      expect(data.scoringConfig?.scoringPresetId).toBe('preset-1');
    });

    it('should handle league without owner', async () => {
      // Arrange
      const leagueId = 'league-2';
      const mockLeaguesData = {
        leagues: [
          {
            id: 'league-2',
            name: 'League Without Owner',
            description: 'A league without an owner',
            capacity: 15,
            currentMembers: 8,
            // No ownerId
            status: 'active' as const,
            createdAt: new Date().toISOString(),
            updatedAt: new Date().toISOString(),
          },
        ],
      };
      const mockMembershipsData = createMockMembershipsData();
      const mockRacesPageData = createMockRacesPageData();

      global.fetch = vi.fn((url: string) => {
        if (url.includes('/leagues/all-with-capacity-and-scoring')) {
          return Promise.resolve(createMockResponse(mockLeaguesData));
        }
        if (url.includes('/memberships')) {
          return Promise.resolve(createMockResponse(mockMembershipsData));
        }
        if (url.includes('/races/page-data')) {
          return Promise.resolve(createMockResponse(mockRacesPageData));
        }
        return Promise.resolve(createMockErrorResponse(404, 'Not Found', 'Not Found'));
      });
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isOk()).toBe(true);
      const data = result.unwrap();
      
      expect(data.owner).toBeNull();
      expect(data.league.id).toBe('league-2');
      expect(data.league.name).toBe('League Without Owner');
    });

    it('should handle league with no races', async () => {
      // Arrange
      const leagueId = 'league-3';
      const mockLeaguesData = createMockLeagueDetailData();
      const mockMembershipsData = createMockMembershipsData();
      const mockRacesPageData = { races: [] };

      global.fetch = vi.fn((url: string) => {
        if (url.includes('/leagues/all-with-capacity-and-scoring')) {
          return Promise.resolve(createMockResponse(mockLeaguesData));
        }
        if (url.includes('/memberships')) {
          return Promise.resolve(createMockResponse(mockMembershipsData));
        }
        if (url.includes('/races/page-data')) {
          return Promise.resolve(createMockResponse(mockRacesPageData));
        }
        return Promise.resolve(createMockErrorResponse(404, 'Not Found', 'Not Found'));
      });
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isOk()).toBe(true);
      const data = result.unwrap();
      
      expect(data.races).toBeDefined();
      expect(data.races.length).toBe(0);
    });
  });

  describe('Error Handling', () => {
    it('should handle 404 error when league not found', async () => {
      // Arrange
      const leagueId = 'non-existent-league';
      
      global.fetch = vi.fn((url: string) => {
        if (url.includes('/leagues/all-with-capacity-and-scoring')) {
          return Promise.resolve(createMockResponse({ leagues: [] }));
        }
        return Promise.resolve(createMockErrorResponse(404, 'Not Found', 'League not found'));
      });
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isErr()).toBe(true);
      const error = result.getError();
      expect(error).toBe('notFound');
    });

    it('should handle 500 error when API server error', async () => {
      // Arrange
      const leagueId = 'league-1';
      
      global.fetch = vi.fn((url: string) => {
        if (url.includes('/leagues/all-with-capacity-and-scoring')) {
          return Promise.resolve(createMockErrorResponse(500, 'Internal Server Error', 'Internal Server Error'));
        }
        return Promise.resolve(createMockErrorResponse(500, 'Internal Server Error', 'Internal Server Error'));
      });
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isErr()).toBe(true);
      const error = result.getError();
      expect(error).toBe('serverError');
    });

    it('should handle network error', async () => {
      // Arrange
      const leagueId = 'league-1';
      
      global.fetch = vi.fn().mockRejectedValue(new Error('Network error: Unable to reach the API server'));
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isErr()).toBe(true);
      const error = result.getError();
      expect(error).toBe('serverError');
    });

    it('should handle timeout error', async () => {
      // Arrange
      const leagueId = 'league-1';
      const timeoutError = new Error('Request timed out after 30 seconds');
      timeoutError.name = 'AbortError';
      
      global.fetch = vi.fn().mockRejectedValue(timeoutError);
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isErr()).toBe(true);
      const error = result.getError();
      expect(error).toBe('serverError');
    });

    it('should handle unauthorized error', async () => {
      // Arrange
      const leagueId = 'league-1';
      
      global.fetch = vi.fn((url: string) => {
        if (url.includes('/leagues/all-with-capacity-and-scoring')) {
          return Promise.resolve({
            ok: false,
            status: 401,
            statusText: 'Unauthorized',
            text: async () => 'Unauthorized',
          });
        }
        return Promise.resolve({
          ok: false,
          status: 401,
          statusText: 'Unauthorized',
          text: async () => 'Unauthorized',
        });
      });
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isErr()).toBe(true);
      const error = result.getError();
      expect(error).toBe('unauthorized');
    });

    it('should handle forbidden error', async () => {
      // Arrange
      const leagueId = 'league-1';
      
      global.fetch = vi.fn((url: string) => {
        if (url.includes('/leagues/all-with-capacity-and-scoring')) {
          return Promise.resolve({
            ok: false,
            status: 403,
            statusText: 'Forbidden',
            text: async () => 'Forbidden',
          });
        }
        return Promise.resolve({
          ok: false,
          status: 403,
          statusText: 'Forbidden',
          text: async () => 'Forbidden',
        });
      });
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isErr()).toBe(true);
      const error = result.getError();
      expect(error).toBe('unauthorized');
    });
  });

  describe('Missing Data', () => {
    it('should handle API returning partial data (missing memberships)', async () => {
      // Arrange
      const leagueId = 'league-1';
      const mockLeaguesData = createMockLeagueDetailData();
      const mockRacesPageData = createMockRacesPageData();

      global.fetch = vi.fn((url: string) => {
        if (url.includes('/leagues/all-with-capacity-and-scoring')) {
          return Promise.resolve({
            ok: true,
            json: async () => mockLeaguesData,
          });
        }
        if (url.includes('/memberships')) {
          return Promise.resolve({
            ok: true,
            json: async () => ({ members: [] }),
          });
        }
        if (url.includes('/races/page-data')) {
          return Promise.resolve({
            ok: true,
            json: async () => mockRacesPageData,
          });
        }
        return Promise.resolve({
          ok: false,
          status: 404,
          statusText: 'Not Found',
          text: async () => 'Not Found',
        });
      });
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isOk()).toBe(true);
      const data = result.unwrap();
      
      expect(data.memberships).toBeDefined();
      expect(data.memberships.members).toBeDefined();
      expect(data.memberships.members.length).toBe(0);
    });

    it('should handle API returning partial data (missing races)', async () => {
      // Arrange
      const leagueId = 'league-1';
      const mockLeaguesData = createMockLeagueDetailData();
      const mockMembershipsData = createMockMembershipsData();

      global.fetch = vi.fn((url: string) => {
        if (url.includes('/leagues/all-with-capacity-and-scoring')) {
          return Promise.resolve({
            ok: true,
            json: async () => mockLeaguesData,
          });
        }
        if (url.includes('/memberships')) {
          return Promise.resolve({
            ok: true,
            json: async () => mockMembershipsData,
          });
        }
        if (url.includes('/races/page-data')) {
          return Promise.resolve({
            ok: true,
            json: async () => ({ races: [] }),
          });
        }
        return Promise.resolve({
          ok: false,
          status: 404,
          statusText: 'Not Found',
          text: async () => 'Not Found',
        });
      });
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isOk()).toBe(true);
      const data = result.unwrap();
      
      expect(data.races).toBeDefined();
      expect(data.races.length).toBe(0);
    });

    it('should handle API returning partial data (missing scoring config)', async () => {
      // Arrange
      const leagueId = 'league-1';
      const mockLeaguesData = createMockLeagueDetailData();
      const mockMembershipsData = createMockMembershipsData();
      const mockRacesPageData = createMockRacesPageData();

      global.fetch = vi.fn((url: string) => {
        if (url.includes('/leagues/all-with-capacity-and-scoring')) {
          return Promise.resolve({
            ok: true,
            json: async () => mockLeaguesData,
          });
        }
        if (url.includes('/memberships')) {
          return Promise.resolve({
            ok: true,
            json: async () => mockMembershipsData,
          });
        }
        if (url.includes('/races/page-data')) {
          return Promise.resolve({
            ok: true,
            json: async () => mockRacesPageData,
          });
        }
        if (url.includes('/config')) {
          return Promise.resolve({
            ok: false,
            status: 404,
            statusText: 'Not Found',
            text: async () => 'Config not found',
          });
        }
        return Promise.resolve({
          ok: false,
          status: 404,
          statusText: 'Not Found',
          text: async () => 'Not Found',
        });
      });
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isOk()).toBe(true);
      const data = result.unwrap();
      
      expect(data.scoringConfig).toBeNull();
    });

    it('should handle API returning partial data (missing owner)', async () => {
      // Arrange
      const leagueId = 'league-1';
      const mockLeaguesData = {
        leagues: [
          {
            id: 'league-1',
            name: 'Test League',
            description: 'A test league',
            capacity: 10,
            currentMembers: 5,
            ownerId: 'driver-1',
            status: 'active' as const,
            createdAt: new Date().toISOString(),
            updatedAt: new Date().toISOString(),
          },
        ],
      };
      const mockMembershipsData = createMockMembershipsData();
      const mockRacesPageData = createMockRacesPageData();

      global.fetch = vi.fn((url: string) => {
        if (url.includes('/leagues/all-with-capacity-and-scoring')) {
          return Promise.resolve({
            ok: true,
            json: async () => mockLeaguesData,
          });
        }
        if (url.includes('/memberships')) {
          return Promise.resolve({
            ok: true,
            json: async () => mockMembershipsData,
          });
        }
        if (url.includes('/races/page-data')) {
          return Promise.resolve({
            ok: true,
            json: async () => mockRacesPageData,
          });
        }
        if (url.includes('/drivers/driver-1')) {
          return Promise.resolve({
            ok: false,
            status: 404,
            statusText: 'Not Found',
            text: async () => 'Driver not found',
          });
        }
        return Promise.resolve({
          ok: false,
          status: 404,
          statusText: 'Not Found',
          text: async () => 'Not Found',
        });
      });
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isOk()).toBe(true);
      const data = result.unwrap();
      
      expect(data.owner).toBeNull();
    });
  });

  describe('Edge Cases', () => {
    it('should handle API returning empty leagues array', async () => {
      // Arrange
      const leagueId = 'league-1';
      
      global.fetch = vi.fn((url: string) => {
        if (url.includes('/leagues/all-with-capacity-and-scoring')) {
          return Promise.resolve({
            ok: true,
            json: async () => ({ leagues: [] }),
          });
        }
        return Promise.resolve({
          ok: false,
          status: 404,
          statusText: 'Not Found',
          text: async () => 'Not Found',
        });
      });
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isErr()).toBe(true);
      const error = result.getError();
      expect(error.type).toBe('notFound');
      expect(error.message).toContain('Leagues not found');
    });

    it('should handle API returning null data', async () => {
      // Arrange
      const leagueId = 'league-1';
      
      global.fetch = vi.fn((url: string) => {
        if (url.includes('/leagues/all-with-capacity-and-scoring')) {
          return Promise.resolve({
            ok: true,
            json: async () => null,
          });
        }
        return Promise.resolve({
          ok: false,
          status: 404,
          statusText: 'Not Found',
          text: async () => 'Not Found',
        });
      });
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isErr()).toBe(true);
      const error = result.getError();
      expect(error.type).toBe('notFound');
      expect(error.message).toContain('Leagues not found');
    });

    it('should handle API returning malformed data', async () => {
      // Arrange
      const leagueId = 'league-1';
      
      global.fetch = vi.fn((url: string) => {
        if (url.includes('/leagues/all-with-capacity-and-scoring')) {
          return Promise.resolve({
            ok: true,
            json: async () => ({ someOtherProperty: 'value' }),
          });
        }
        return Promise.resolve({
          ok: false,
          status: 404,
          statusText: 'Not Found',
          text: async () => 'Not Found',
        });
      });
      
      // Act
      const result = await LeagueDetailPageQuery.execute(leagueId);

      // Assert
      expect(result.isErr()).toBe(true);
      const error = result.getError();
      expect(error.type).toBe('notFound');
      expect(error.message).toContain('Leagues not found');
    });
  });
});
