import { describe, it, expect, vi, Mocked } from 'vitest';
import { PenaltyService } from './PenaltyService';
import { PenaltiesApiClient } from '@/lib/api/penalties/PenaltiesApiClient';

describe('PenaltyService', () => {
  let mockApiClient: Mocked<PenaltiesApiClient>;
  let service: PenaltyService;

  beforeEach(() => {
    mockApiClient = {
      getRacePenalties: vi.fn(),
      getPenaltyTypesReference: vi.fn(),
      applyPenalty: vi.fn(),
    } as unknown as Mocked<PenaltiesApiClient>;

    service = new PenaltyService(mockApiClient);
  });

  describe('findByRaceId', () => {
    it('should call apiClient.getRacePenalties and return penalties array', async () => {
      const raceId = 'race-123';
      const mockDto = {
        penalties: [
          { id: 'penalty-1', driverId: 'driver-1', type: 'time', value: 5, reason: 'Incident' },
          { id: 'penalty-2', driverId: 'driver-2', type: 'grid', value: 3, reason: 'Qualifying incident' },
        ],
        driverMap: {},
      };

      mockApiClient.getRacePenalties.mockResolvedValue(mockDto as any);

      const result = await service.findByRaceId(raceId);

      expect(mockApiClient.getRacePenalties).toHaveBeenCalledWith(raceId);
      expect(result).toEqual(mockDto.penalties);
      expect(result).toHaveLength(2);
    });

    it('should handle empty penalties array', async () => {
      const raceId = 'race-123';
      const mockDto = { penalties: [], driverMap: {} };

      mockApiClient.getRacePenalties.mockResolvedValue(mockDto as any);

      const result = await service.findByRaceId(raceId);

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

    it('should throw error when apiClient.getRacePenalties fails', async () => {
      const raceId = 'race-123';
      const error = new Error('API call failed');
      mockApiClient.getRacePenalties.mockRejectedValue(error);

      await expect(service.findByRaceId(raceId)).rejects.toThrow('API call failed');
    });
  });

  describe('applyPenalty', () => {
    it('should call apiClient.applyPenalty with input', async () => {
      const input = {
        driverId: 'driver-123',
        raceId: 'race-456',
        type: 'time',
        value: 10,
        reason: 'Test reason',
      };

      mockApiClient.applyPenalty.mockResolvedValue(undefined);

      await service.applyPenalty(input);

      expect(mockApiClient.applyPenalty).toHaveBeenCalledWith(input);
    });

    it('should throw error when apiClient.applyPenalty fails', async () => {
      const input = {
        driverId: 'driver-123',
        raceId: 'race-456',
        type: 'time',
        value: 10,
        reason: 'Test reason',
      };

      const error = new Error('API call failed');
      mockApiClient.applyPenalty.mockRejectedValue(error);

      await expect(service.applyPenalty(input)).rejects.toThrow('API call failed');
    });
  });
});