import React from 'react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';

import LeagueMembers from './LeagueMembers';
import type { DriverDTO } from '@/lib/types/generated/DriverDTO';

// Stub global driver stats helper used by LeagueMembers sorting/rendering
(globalThis as any).getDriverStats = (driverId: string) => ({
  driverId,
  rating: driverId === 'driver-1' ? 2500 : 2000,
  overallRank: driverId === 'driver-1' ? 1 : 2,
  wins: driverId === 'driver-1' ? 10 : 5,
});

// Mock effective driver id so we can assert the "(You)" label
vi.mock('@/hooks/useEffectiveDriverId', () => {
  return {
    useEffectiveDriverId: () => 'driver-1',
  };
});

// Mock services hook to inject stub leagueMembershipService and driverService
const mockFetchLeagueMemberships = vi.fn<[], Promise<any[]>>();
const mockGetLeagueMembers = vi.fn<(leagueId: string) => any[]>();
const mockFindByIds = vi.fn<(ids: string[]) => Promise<DriverDTO[]>>();

vi.mock('@/lib/services/ServiceProvider', () => {
  return {
    useServices: () => ({
      leagueMembershipService: {
        fetchLeagueMemberships: mockFetchLeagueMemberships,
        getLeagueMembers: mockGetLeagueMembers,
      },
      driverService: {
        findByIds: mockFindByIds,
      },
    }),
  };
});

describe('LeagueMembers', () => {
  beforeEach(() => {
    mockFetchLeagueMemberships.mockReset();
    mockGetLeagueMembers.mockReset();
    mockFindByIds.mockReset();
  });

  it('loads memberships via services and renders driver rows', async () => {
    const leagueId = 'league-1';

    const memberships = [
      {
        id: 'm1',
        leagueId,
        driverId: 'driver-1',
        role: 'owner',
        status: 'active',
        joinedAt: '2024-01-01T00:00:00.000Z',
      },
      {
        id: 'm2',
        leagueId,
        driverId: 'driver-2',
        role: 'member',
        status: 'active',
        joinedAt: '2024-01-02T00:00:00.000Z',
      },
    ];

    const drivers: DriverDTO[] = [
      {
        id: 'driver-1',
        iracingId: 'ir-1',
        name: 'Driver One',
        country: 'DE',
      },
      {
        id: 'driver-2',
        iracingId: 'ir-2',
        name: 'Driver Two',
        country: 'US',
      },
    ];

    mockFetchLeagueMemberships.mockResolvedValue(memberships);
    mockGetLeagueMembers.mockReturnValue(memberships);
    mockFindByIds.mockResolvedValue(drivers);

    render(<LeagueMembers leagueId={leagueId} showActions={false} />);

    // Loading state first
    expect(screen.getByText('Loading members...')).toBeInTheDocument();

    // Wait for data to be rendered
    await waitFor(() => {
      expect(screen.queryByText('Loading members...')).not.toBeInTheDocument();
    });

    // Services should have been called with expected arguments
    expect(mockFetchLeagueMemberships).toHaveBeenCalledWith(leagueId);
    expect(mockGetLeagueMembers).toHaveBeenCalledWith(leagueId);
    expect(mockFindByIds).toHaveBeenCalledTimes(1);
    expect(mockFindByIds).toHaveBeenCalledWith(['driver-1', 'driver-2']);

    // Driver rows should be rendered using DTO names
    expect(screen.getByText('Driver One')).toBeInTheDocument();
    expect(screen.getByText('Driver Two')).toBeInTheDocument();

    // Current user marker should appear for effective driver id
    expect(screen.getByText('(You)')).toBeInTheDocument();
  });

  it('handles empty membership list gracefully', async () => {
    const leagueId = 'league-empty';

    mockFetchLeagueMemberships.mockResolvedValue([]);
    mockGetLeagueMembers.mockReturnValue([]);
    mockFindByIds.mockResolvedValue([]);

    render(<LeagueMembers leagueId={leagueId} showActions={false} />);

    await waitFor(() => {
      expect(screen.queryByText('Loading members...')).not.toBeInTheDocument();
    });

    expect(screen.getByText('No members found')).toBeInTheDocument();
  });
});
