/**
 * League API Tests
 * 
 * This test suite performs comprehensive API testing for league-related endpoints.
 * It validates:
 * - Response structure matches expected DTO
 * - Required fields are present
 * - Data types are correct
 * - Edge cases (empty results, missing data)
 * - Business logic (sorting, filtering, calculations)
 * 
 * This test is designed to run in the Docker e2e environment and can be executed with:
 * npm run test:e2e:website (which runs everything in Docker)
 */

import { test, expect, request } from '@playwright/test';
import * as fs from 'fs/promises';
import * as path from 'path';

interface TestResult {
  endpoint: string;
  method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
  status: number;
  success: boolean;
  error?: string;
  response?: unknown;
  hasPresenterError: boolean;
  responseTime: number;
}

const API_BASE_URL = process.env.API_BASE_URL ?? process.env.NEXT_PUBLIC_API_BASE_URL ?? 'http://localhost:3101';

// Auth file paths
const USER_AUTH_FILE = path.join(__dirname, '.auth/user-session.json');
const ADMIN_AUTH_FILE = path.join(__dirname, '.auth/admin-session.json');

test.describe('League API Tests', () => {
  const allResults: TestResult[] = [];
  let testResults: TestResult[] = [];

  test.beforeAll(async () => {
    console.log(`[LEAGUE API] Testing API at: ${API_BASE_URL}`);
    
    // Verify auth files exist
    const userAuthExists = await fs.access(USER_AUTH_FILE).then(() => true).catch(() => false);
    const adminAuthExists = await fs.access(ADMIN_AUTH_FILE).then(() => true).catch(() => false);
    
    if (!userAuthExists || !adminAuthExists) {
      throw new Error('Auth files not found. Run global setup first.');
    }
    
    console.log('[LEAGUE API] Auth files verified');
  });

  test.afterAll(async () => {
    await generateReport();
  });

  test('League Discovery Endpoints - Public endpoints', async ({ request }) => {
    testResults = [];
    const endpoints = [
      { method: 'GET' as const, path: '/leagues/all-with-capacity', name: 'Get all leagues with capacity' },
      { method: 'GET' as const, path: '/leagues/all-with-capacity-and-scoring', name: 'Get all leagues with capacity and scoring' },
      { method: 'GET' as const, path: '/leagues/total-leagues', name: 'Get total leagues count' },
      { method: 'GET' as const, path: '/leagues/all', name: 'Get all leagues (alias)' },
      { method: 'GET' as const, path: '/leagues/available', name: 'Get available leagues (alias)' },
    ];

    console.log(`\n[LEAGUE API] Testing ${endpoints.length} league discovery endpoints...`);

    for (const endpoint of endpoints) {
      await testEndpoint(request, endpoint);
    }

    // Check for failures
    const failures = testResults.filter(r => !r.success);
    if (failures.length > 0) {
      console.log('\n❌ FAILURES FOUND:');
      failures.forEach(r => {
        console.log(`  ${r.method} ${r.endpoint} - ${r.status} - ${r.error || r.response}`);
      });
    }

    // Assert all endpoints succeeded
    expect(failures.length).toBe(0);
  });

  test('League Discovery - Response structure validation', async ({ request }) => {
    testResults = [];
    
    // Test /leagues/all-with-capacity
    const allLeaguesResponse = await request.get(`${API_BASE_URL}/leagues/all-with-capacity`);
    expect(allLeaguesResponse.ok()).toBe(true);
    
    const allLeaguesData = await allLeaguesResponse.json();
    expect(allLeaguesData).toHaveProperty('leagues');
    expect(allLeaguesData).toHaveProperty('totalCount');
    expect(Array.isArray(allLeaguesData.leagues)).toBe(true);
    expect(typeof allLeaguesData.totalCount).toBe('number');
    
    // Validate league structure if leagues exist
    if (allLeaguesData.leagues.length > 0) {
      const league = allLeaguesData.leagues[0];
      expect(league).toHaveProperty('id');
      expect(league).toHaveProperty('name');
      expect(league).toHaveProperty('description');
      expect(league).toHaveProperty('ownerId');
      expect(league).toHaveProperty('createdAt');
      expect(league).toHaveProperty('settings');
      expect(league.settings).toHaveProperty('maxDrivers');
      expect(league).toHaveProperty('usedSlots');
      
      // Validate data types
      expect(typeof league.id).toBe('string');
      expect(typeof league.name).toBe('string');
      expect(typeof league.description).toBe('string');
      expect(typeof league.ownerId).toBe('string');
      expect(typeof league.createdAt).toBe('string');
      expect(typeof league.settings.maxDrivers).toBe('number');
      expect(typeof league.usedSlots).toBe('number');
      
      // Validate business logic: usedSlots <= maxDrivers
      expect(league.usedSlots).toBeLessThanOrEqual(league.settings.maxDrivers);
    }
    
    // Test /leagues/all-with-capacity-and-scoring
    const scoredLeaguesResponse = await request.get(`${API_BASE_URL}/leagues/all-with-capacity-and-scoring`);
    expect(scoredLeaguesResponse.ok()).toBe(true);
    
    const scoredLeaguesData = await scoredLeaguesResponse.json();
    expect(scoredLeaguesData).toHaveProperty('leagues');
    expect(scoredLeaguesData).toHaveProperty('totalCount');
    expect(Array.isArray(scoredLeaguesData.leagues)).toBe(true);
    
    // Validate scoring structure if leagues exist
    if (scoredLeaguesData.leagues.length > 0) {
      const league = scoredLeaguesData.leagues[0];
      expect(league).toHaveProperty('scoring');
      expect(league.scoring).toHaveProperty('gameId');
      expect(league.scoring).toHaveProperty('scoringPresetId');
      
      // Validate data types
      expect(typeof league.scoring.gameId).toBe('string');
      expect(typeof league.scoring.scoringPresetId).toBe('string');
    }
    
    // Test /leagues/total-leagues
    const totalResponse = await request.get(`${API_BASE_URL}/leagues/total-leagues`);
    expect(totalResponse.ok()).toBe(true);
    
    const totalData = await totalResponse.json();
    expect(totalData).toHaveProperty('totalLeagues');
    expect(typeof totalData.totalLeagues).toBe('number');
    expect(totalData.totalLeagues).toBeGreaterThanOrEqual(0);
    
    // Validate consistency: totalCount from all-with-capacity should match totalLeagues
    expect(allLeaguesData.totalCount).toBe(totalData.totalLeagues);
    
    testResults.push({
      endpoint: '/leagues/all-with-capacity',
      method: 'GET',
      status: allLeaguesResponse.status(),
      success: true,
      hasPresenterError: false,
      responseTime: 0,
    });
    
    testResults.push({
      endpoint: '/leagues/all-with-capacity-and-scoring',
      method: 'GET',
      status: scoredLeaguesResponse.status(),
      success: true,
      hasPresenterError: false,
      responseTime: 0,
    });
    
    testResults.push({
      endpoint: '/leagues/total-leagues',
      method: 'GET',
      status: totalResponse.status(),
      success: true,
      hasPresenterError: false,
      responseTime: 0,
    });
    
    allResults.push(...testResults);
  });

  test('League Detail Endpoints - Public endpoints', async ({ request }) => {
    testResults = [];
    
    // First, get a valid league ID from the discovery endpoint
    const discoveryResponse = await request.get(`${API_BASE_URL}/leagues/all-with-capacity`);
    const discoveryData = await discoveryResponse.json();
    
    if (discoveryData.leagues.length === 0) {
      console.log('[LEAGUE API] No leagues found, skipping detail endpoint tests');
      return;
    }
    
    const leagueId = discoveryData.leagues[0].id;
    
    const endpoints = [
      { method: 'GET' as const, path: `/leagues/${leagueId}`, name: 'Get league details' },
      { method: 'GET' as const, path: `/leagues/${leagueId}/seasons`, name: 'Get league seasons' },
      { method: 'GET' as const, path: `/leagues/${leagueId}/stats`, name: 'Get league stats' },
      { method: 'GET' as const, path: `/leagues/${leagueId}/memberships`, name: 'Get league memberships' },
    ];

    console.log(`\n[LEAGUE API] Testing ${endpoints.length} league detail endpoints for league ${leagueId}...`);

    for (const endpoint of endpoints) {
      await testEndpoint(request, endpoint);
    }

    // Check for failures
    const failures = testResults.filter(r => !r.success);
    if (failures.length > 0) {
      console.log('\n❌ FAILURES FOUND:');
      failures.forEach(r => {
        console.log(`  ${r.method} ${r.endpoint} - ${r.status} - ${r.error || r.response}`);
      });
    }

    // Assert all endpoints succeeded
    expect(failures.length).toBe(0);
  });

  test('League Detail - Response structure validation', async ({ request }) => {
    testResults = [];
    
    // First, get a valid league ID from the discovery endpoint
    const discoveryResponse = await request.get(`${API_BASE_URL}/leagues/all-with-capacity`);
    const discoveryData = await discoveryResponse.json();
    
    if (discoveryData.leagues.length === 0) {
      console.log('[LEAGUE API] No leagues found, skipping detail validation tests');
      return;
    }
    
    const leagueId = discoveryData.leagues[0].id;
    
    // Test /leagues/{id}
    const leagueResponse = await request.get(`${API_BASE_URL}/leagues/${leagueId}`);
    expect(leagueResponse.ok()).toBe(true);
    
    const leagueData = await leagueResponse.json();
    expect(leagueData).toHaveProperty('id');
    expect(leagueData).toHaveProperty('name');
    expect(leagueData).toHaveProperty('description');
    expect(leagueData).toHaveProperty('ownerId');
    expect(leagueData).toHaveProperty('createdAt');
    
    // Validate data types
    expect(typeof leagueData.id).toBe('string');
    expect(typeof leagueData.name).toBe('string');
    expect(typeof leagueData.description).toBe('string');
    expect(typeof leagueData.ownerId).toBe('string');
    expect(typeof leagueData.createdAt).toBe('string');
    
    // Validate ID matches requested ID
    expect(leagueData.id).toBe(leagueId);
    
    // Test /leagues/{id}/seasons
    const seasonsResponse = await request.get(`${API_BASE_URL}/leagues/${leagueId}/seasons`);
    expect(seasonsResponse.ok()).toBe(true);
    
    const seasonsData = await seasonsResponse.json();
    expect(Array.isArray(seasonsData)).toBe(true);
    
    // Validate season structure if seasons exist
    if (seasonsData.length > 0) {
      const season = seasonsData[0];
      expect(season).toHaveProperty('id');
      expect(season).toHaveProperty('name');
      expect(season).toHaveProperty('status');
      
      // Validate data types
      expect(typeof season.id).toBe('string');
      expect(typeof season.name).toBe('string');
      expect(typeof season.status).toBe('string');
    }
    
    // Test /leagues/{id}/stats
    const statsResponse = await request.get(`${API_BASE_URL}/leagues/${leagueId}/stats`);
    expect(statsResponse.ok()).toBe(true);
    
    const statsData = await statsResponse.json();
    expect(statsData).toHaveProperty('memberCount');
    expect(statsData).toHaveProperty('raceCount');
    expect(statsData).toHaveProperty('avgSOF');
    
    // Validate data types
    expect(typeof statsData.memberCount).toBe('number');
    expect(typeof statsData.raceCount).toBe('number');
    expect(typeof statsData.avgSOF).toBe('number');
    
    // Validate business logic: counts should be non-negative
    expect(statsData.memberCount).toBeGreaterThanOrEqual(0);
    expect(statsData.raceCount).toBeGreaterThanOrEqual(0);
    expect(statsData.avgSOF).toBeGreaterThanOrEqual(0);
    
    // Test /leagues/{id}/memberships
    const membershipsResponse = await request.get(`${API_BASE_URL}/leagues/${leagueId}/memberships`);
    expect(membershipsResponse.ok()).toBe(true);
    
    const membershipsData = await membershipsResponse.json();
    expect(membershipsData).toHaveProperty('members');
    expect(Array.isArray(membershipsData.members)).toBe(true);
    
    // Validate membership structure if members exist
    if (membershipsData.members.length > 0) {
      const member = membershipsData.members[0];
      expect(member).toHaveProperty('driverId');
      expect(member).toHaveProperty('role');
      expect(member).toHaveProperty('joinedAt');
      
      // Validate data types
      expect(typeof member.driverId).toBe('string');
      expect(typeof member.role).toBe('string');
      expect(typeof member.joinedAt).toBe('string');
      
      // Validate business logic: at least one owner must exist
      const hasOwner = membershipsData.members.some((m: any) => m.role === 'owner');
      expect(hasOwner).toBe(true);
    }
    
    testResults.push({
      endpoint: `/leagues/${leagueId}`,
      method: 'GET',
      status: leagueResponse.status(),
      success: true,
      hasPresenterError: false,
      responseTime: 0,
    });
    
    testResults.push({
      endpoint: `/leagues/${leagueId}/seasons`,
      method: 'GET',
      status: seasonsResponse.status(),
      success: true,
      hasPresenterError: false,
      responseTime: 0,
    });
    
    testResults.push({
      endpoint: `/leagues/${leagueId}/stats`,
      method: 'GET',
      status: statsResponse.status(),
      success: true,
      hasPresenterError: false,
      responseTime: 0,
    });
    
    testResults.push({
      endpoint: `/leagues/${leagueId}/memberships`,
      method: 'GET',
      status: membershipsResponse.status(),
      success: true,
      hasPresenterError: false,
      responseTime: 0,
    });
    
    allResults.push(...testResults);
  });

  test('League Schedule Endpoints - Public endpoints', async ({ request }) => {
    testResults = [];
    
    // First, get a valid league ID from the discovery endpoint
    const discoveryResponse = await request.get(`${API_BASE_URL}/leagues/all-with-capacity`);
    const discoveryData = await discoveryResponse.json();
    
    if (discoveryData.leagues.length === 0) {
      console.log('[LEAGUE API] No leagues found, skipping schedule endpoint tests');
      return;
    }
    
    const leagueId = discoveryData.leagues[0].id;
    
    const endpoints = [
      { method: 'GET' as const, path: `/leagues/${leagueId}/schedule`, name: 'Get league schedule' },
    ];

    console.log(`\n[LEAGUE API] Testing ${endpoints.length} league schedule endpoints for league ${leagueId}...`);

    for (const endpoint of endpoints) {
      await testEndpoint(request, endpoint);
    }

    // Check for failures
    const failures = testResults.filter(r => !r.success);
    if (failures.length > 0) {
      console.log('\n❌ FAILURES FOUND:');
      failures.forEach(r => {
        console.log(`  ${r.method} ${r.endpoint} - ${r.status} - ${r.error || r.response}`);
      });
    }

    // Assert all endpoints succeeded
    expect(failures.length).toBe(0);
  });

  test('League Schedule - Response structure validation', async ({ request }) => {
    testResults = [];
    
    // First, get a valid league ID from the discovery endpoint
    const discoveryResponse = await request.get(`${API_BASE_URL}/leagues/all-with-capacity`);
    const discoveryData = await discoveryResponse.json();
    
    if (discoveryData.leagues.length === 0) {
      console.log('[LEAGUE API] No leagues found, skipping schedule validation tests');
      return;
    }
    
    const leagueId = discoveryData.leagues[0].id;
    
    // Test /leagues/{id}/schedule
    const scheduleResponse = await request.get(`${API_BASE_URL}/leagues/${leagueId}/schedule`);
    expect(scheduleResponse.ok()).toBe(true);
    
    const scheduleData = await scheduleResponse.json();
    expect(scheduleData).toHaveProperty('seasonId');
    expect(scheduleData).toHaveProperty('races');
    expect(Array.isArray(scheduleData.races)).toBe(true);
    
    // Validate data types
    expect(typeof scheduleData.seasonId).toBe('string');
    
    // Validate race structure if races exist
    if (scheduleData.races.length > 0) {
      const race = scheduleData.races[0];
      expect(race).toHaveProperty('id');
      expect(race).toHaveProperty('track');
      expect(race).toHaveProperty('car');
      expect(race).toHaveProperty('scheduledAt');
      
      // Validate data types
      expect(typeof race.id).toBe('string');
      expect(typeof race.track).toBe('string');
      expect(typeof race.car).toBe('string');
      expect(typeof race.scheduledAt).toBe('string');
      
      // Validate business logic: races should be sorted by scheduledAt
      const scheduledTimes = scheduleData.races.map((r: any) => new Date(r.scheduledAt).getTime());
      const sortedTimes = [...scheduledTimes].sort((a, b) => a - b);
      expect(scheduledTimes).toEqual(sortedTimes);
    }
    
    testResults.push({
      endpoint: `/leagues/${leagueId}/schedule`,
      method: 'GET',
      status: scheduleResponse.status(),
      success: true,
      hasPresenterError: false,
      responseTime: 0,
    });
    
    allResults.push(...testResults);
  });

  test('League Standings Endpoints - Public endpoints', async ({ request }) => {
    testResults = [];
    
    // First, get a valid league ID from the discovery endpoint
    const discoveryResponse = await request.get(`${API_BASE_URL}/leagues/all-with-capacity`);
    const discoveryData = await discoveryResponse.json();
    
    if (discoveryData.leagues.length === 0) {
      console.log('[LEAGUE API] No leagues found, skipping standings endpoint tests');
      return;
    }
    
    const leagueId = discoveryData.leagues[0].id;
    
    const endpoints = [
      { method: 'GET' as const, path: `/leagues/${leagueId}/standings`, name: 'Get league standings' },
    ];

    console.log(`\n[LEAGUE API] Testing ${endpoints.length} league standings endpoints for league ${leagueId}...`);

    for (const endpoint of endpoints) {
      await testEndpoint(request, endpoint);
    }

    // Check for failures
    const failures = testResults.filter(r => !r.success);
    if (failures.length > 0) {
      console.log('\n❌ FAILURES FOUND:');
      failures.forEach(r => {
        console.log(`  ${r.method} ${r.endpoint} - ${r.status} - ${r.error || r.response}`);
      });
    }

    // Assert all endpoints succeeded
    expect(failures.length).toBe(0);
  });

  test('League Standings - Response structure validation', async ({ request }) => {
    testResults = [];
    
    // First, get a valid league ID from the discovery endpoint
    const discoveryResponse = await request.get(`${API_BASE_URL}/leagues/all-with-capacity`);
    const discoveryData = await discoveryResponse.json();
    
    if (discoveryData.leagues.length === 0) {
      console.log('[LEAGUE API] No leagues found, skipping standings validation tests');
      return;
    }
    
    const leagueId = discoveryData.leagues[0].id;
    
    // Test /leagues/{id}/standings
    const standingsResponse = await request.get(`${API_BASE_URL}/leagues/${leagueId}/standings`);
    expect(standingsResponse.ok()).toBe(true);
    
    const standingsData = await standingsResponse.json();
    expect(standingsData).toHaveProperty('standings');
    expect(Array.isArray(standingsData.standings)).toBe(true);
    
    // Validate standing structure if standings exist
    if (standingsData.standings.length > 0) {
      const standing = standingsData.standings[0];
      expect(standing).toHaveProperty('position');
      expect(standing).toHaveProperty('driverId');
      expect(standing).toHaveProperty('points');
      expect(standing).toHaveProperty('races');
      
      // Validate data types
      expect(typeof standing.position).toBe('number');
      expect(typeof standing.driverId).toBe('string');
      expect(typeof standing.points).toBe('number');
      expect(typeof standing.races).toBe('number');
      
      // Validate business logic: position must be sequential starting from 1
      const positions = standingsData.standings.map((s: any) => s.position);
      const expectedPositions = Array.from({ length: positions.length }, (_, i) => i + 1);
      expect(positions).toEqual(expectedPositions);
      
      // Validate business logic: points must be non-negative
      expect(standing.points).toBeGreaterThanOrEqual(0);
      
      // Validate business logic: races count must be non-negative
      expect(standing.races).toBeGreaterThanOrEqual(0);
    }
    
    testResults.push({
      endpoint: `/leagues/${leagueId}/standings`,
      method: 'GET',
      status: standingsResponse.status(),
      success: true,
      hasPresenterError: false,
      responseTime: 0,
    });
    
    allResults.push(...testResults);
  });

  test('Edge Cases - Invalid league IDs', async ({ request }) => {
    testResults = [];
    
    const endpoints = [
      { method: 'GET' as const, path: '/leagues/non-existent-league-id', name: 'Get non-existent league' },
      { method: 'GET' as const, path: '/leagues/non-existent-league-id/seasons', name: 'Get seasons for non-existent league' },
      { method: 'GET' as const, path: '/leagues/non-existent-league-id/stats', name: 'Get stats for non-existent league' },
      { method: 'GET' as const, path: '/leagues/non-existent-league-id/schedule', name: 'Get schedule for non-existent league' },
      { method: 'GET' as const, path: '/leagues/non-existent-league-id/standings', name: 'Get standings for non-existent league' },
      { method: 'GET' as const, path: '/leagues/non-existent-league-id/memberships', name: 'Get memberships for non-existent league' },
    ];

    console.log(`\n[LEAGUE API] Testing ${endpoints.length} edge case endpoints with invalid IDs...`);

    for (const endpoint of endpoints) {
      await testEndpoint(request, endpoint);
    }

    // Check for failures
    const failures = testResults.filter(r => !r.success);
    if (failures.length > 0) {
      console.log('\n❌ FAILURES FOUND:');
      failures.forEach(r => {
        console.log(`  ${r.method} ${r.endpoint} - ${r.status} - ${r.error || r.response}`);
      });
    }

    // Assert all endpoints succeeded (404 is acceptable for non-existent resources)
    expect(failures.length).toBe(0);
  });

  test('Edge Cases - Empty results', async ({ request }) => {
    testResults = [];
    
    // Test discovery endpoints with filters (if available)
    // Note: The current API doesn't seem to have filter parameters, but we test the base endpoints
    
    const endpoints = [
      { method: 'GET' as const, path: '/leagues/all-with-capacity', name: 'Get all leagues (empty check)' },
      { method: 'GET' as const, path: '/leagues/all-with-capacity-and-scoring', name: 'Get all leagues with scoring (empty check)' },
    ];

    console.log(`\n[LEAGUE API] Testing ${endpoints.length} endpoints for empty result handling...`);

    for (const endpoint of endpoints) {
      await testEndpoint(request, endpoint);
    }

    // Check for failures
    const failures = testResults.filter(r => !r.success);
    if (failures.length > 0) {
      console.log('\n❌ FAILURES FOUND:');
      failures.forEach(r => {
        console.log(`  ${r.method} ${r.endpoint} - ${r.status} - ${r.error || r.response}`);
      });
    }

    // Assert all endpoints succeeded
    expect(failures.length).toBe(0);
  });

  async function testEndpoint(
    request: import('@playwright/test').APIRequestContext,
    endpoint: { method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; path: string; name?: string; body?: unknown; requiresAuth?: boolean }
  ): Promise<void> {
    const startTime = Date.now();
    const fullUrl = `${API_BASE_URL}${endpoint.path}`;
    
    console.log(`\n[TEST] ${endpoint.method} ${endpoint.path} (${endpoint.name || 'Unknown'})`);

    try {
      let response;
      const headers: Record<string, string> = {};
      
      // Playwright's request context handles cookies automatically
      // No need to set Authorization header for cookie-based auth
      
      switch (endpoint.method) {
        case 'GET':
          response = await request.get(fullUrl, { headers });
          break;
        case 'POST':
          response = await request.post(fullUrl, { data: endpoint.body || {}, headers });
          break;
        case 'PUT':
          response = await request.put(fullUrl, { data: endpoint.body || {}, headers });
          break;
        case 'DELETE':
          response = await request.delete(fullUrl, { headers });
          break;
        case 'PATCH':
          response = await request.patch(fullUrl, { data: endpoint.body || {}, headers });
          break;
      }

      const responseTime = Date.now() - startTime;
      const status = response.status();
      const body = await response.json().catch(() => null);
      const bodyText = await response.text().catch(() => '');

      // Check for presenter errors
      const hasPresenterError =
        bodyText.includes('Presenter not presented') ||
        bodyText.includes('presenter not presented') ||
        (body && body.message && body.message.includes('Presenter not presented')) ||
        (body && body.error && body.error.includes('Presenter not presented'));

      // Success is 200-299 status, or 404 for non-existent resources, and no presenter error
      const isNotFound = status === 404;
      const success = (status >= 200 && status < 300 || isNotFound) && !hasPresenterError;

      const result: TestResult = {
        endpoint: endpoint.path,
        method: endpoint.method,
        status,
        success,
        hasPresenterError,
        responseTime,
        response: body || bodyText.substring(0, 200),
      };

      if (!success) {
        result.error = body?.message || bodyText.substring(0, 200);
      }

      testResults.push(result);
      allResults.push(result);

      if (hasPresenterError) {
        console.log(`  ❌ PRESENTER ERROR: ${status} - ${body?.message || bodyText.substring(0, 100)}`);
      } else if (success) {
        console.log(`  ✅ ${status} (${responseTime}ms)`);
      } else {
        console.log(`  ⚠️  ${status} (${responseTime}ms) - ${body?.message || 'Error'}`);
      }

    } catch (error: unknown) {
      const responseTime = Date.now() - startTime;
      const errorString = error instanceof Error ? error.message : String(error);
      
      const result: TestResult = {
        endpoint: endpoint.path,
        method: endpoint.method,
        status: 0,
        success: false,
        hasPresenterError: false,
        responseTime,
        error: errorString,
      };

      // Check if it's a presenter error
      if (errorString.includes('Presenter not presented')) {
        result.hasPresenterError = true;
        console.log(`  ❌ PRESENTER ERROR (exception): ${errorString}`);
      } else {
        console.log(`  ❌ EXCEPTION: ${errorString}`);
      }

      testResults.push(result);
      allResults.push(result);
    }
  }

  async function generateReport(): Promise<void> {
    const summary = {
      total: allResults.length,
      success: allResults.filter(r => r.success).length,
      failed: allResults.filter(r => !r.success).length,
      presenterErrors: allResults.filter(r => r.hasPresenterError).length,
      avgResponseTime: allResults.reduce((sum, r) => sum + r.responseTime, 0) / allResults.length || 0,
    };

    const report = {
      timestamp: new Date().toISOString(),
      summary,
      results: allResults,
      failures: allResults.filter(r => !r.success),
    };

    // Write JSON report
    const jsonPath = path.join(__dirname, '../../../league-api-test-report.json');
    await fs.writeFile(jsonPath, JSON.stringify(report, null, 2));
    
    // Write Markdown report
    const mdPath = path.join(__dirname, '../../../league-api-test-report.md');
    let md = `# League API Test Report\n\n`;
    md += `**Generated:** ${new Date().toISOString()}\n`;
    md += `**API Base URL:** ${API_BASE_URL}\n\n`;
    
    md += `## Summary\n\n`;
    md += `- **Total Endpoints:** ${summary.total}\n`;
    md += `- **✅ Success:** ${summary.success}\n`;
    md += `- **❌ Failed:** ${summary.failed}\n`;
    md += `- **⚠️  Presenter Errors:** ${summary.presenterErrors}\n`;
    md += `- **Avg Response Time:** ${summary.avgResponseTime.toFixed(2)}ms\n\n`;

    if (summary.presenterErrors > 0) {
      md += `## Presenter Errors\n\n`;
      const presenterFailures = allResults.filter(r => r.hasPresenterError);
      presenterFailures.forEach((r, i) => {
        md += `${i + 1}. **${r.method} ${r.endpoint}**\n`;
        md += `   - Status: ${r.status}\n`;
        md += `   - Error: ${r.error || 'No error message'}\n\n`;
      });
    }

    if (summary.failed > 0 && summary.presenterErrors < summary.failed) {
      md += `## Other Failures\n\n`;
      const otherFailures = allResults.filter(r => !r.success && !r.hasPresenterError);
      otherFailures.forEach((r, i) => {
        md += `${i + 1}. **${r.method} ${r.endpoint}**\n`;
        md += `   - Status: ${r.status}\n`;
        md += `   - Error: ${r.error || 'No error message'}\n\n`;
      });
    }

    await fs.writeFile(mdPath, md);

    console.log(`\n📊 Reports generated:`);
    console.log(`  JSON: ${jsonPath}`);
    console.log(`  Markdown: ${mdPath}`);
    console.log(`\nSummary: ${summary.success}/${summary.total} passed, ${summary.presenterErrors} presenter errors`);
  }
});
