import type { GetRacePenaltiesResult } from '@core/racing/application/use-cases/GetRacePenaltiesUseCase';
import { RacePenaltiesPresenter } from './RacePenaltiesPresenter';

describe('RacePenaltiesPresenter', () => {
  let presenter: RacePenaltiesPresenter;

  beforeEach(() => {
    presenter = new RacePenaltiesPresenter();
  });

  describe('present', () => {
    it('should map result to response model', () => {
      const mockPenalty = {
        id: 'penalty-123',
        driverId: 'driver-456',
        type: 'time_penalty',
        value: 10,
        reason: 'Track limits violation',
        issuedBy: 'steward-789',
        issuedAt: new Date('2024-01-01T10:00:00Z'),
        notes: 'Multiple violations',
      };

      const mockDriver = {
        id: 'driver-456',
        name: { toString: () => 'John Doe' } as never,
      };

      const result: GetRacePenaltiesResult = {
        penalties: [mockPenalty as never],
        drivers: [mockDriver as never],
      };

      presenter.present(result);

      expect(presenter.responseModel).toEqual({
        penalties: [
          {
            id: 'penalty-123',
            driverId: 'driver-456',
            type: 'time_penalty',
            value: 10,
            reason: 'Track limits violation',
            issuedBy: 'steward-789',
            issuedAt: '2024-01-01T10:00:00.000Z',
            notes: 'Multiple violations',
          },
        ],
        driverMap: {
          'driver-456': 'John Doe',
        },
      });
    });

    it('should handle multiple penalties and drivers', () => {
      const result: GetRacePenaltiesResult = {
        penalties: [
          {
            id: 'penalty-1',
            driverId: 'driver-1',
            type: 'time_penalty',
            value: 5,
            reason: 'Reason 1',
            issuedBy: 'steward-1',
            issuedAt: new Date('2024-01-01T10:00:00Z'),
          } as never,
          {
            id: 'penalty-2',
            driverId: 'driver-2',
            type: 'drive_through',
            value: 0,
            reason: 'Reason 2',
            issuedBy: 'steward-1',
            issuedAt: new Date('2024-01-01T10:05:00Z'),
          } as never,
        ],
        drivers: [
          { id: 'driver-1', name: { toString: () => 'Driver One' } } as never,
          { id: 'driver-2', name: { toString: () => 'Driver Two' } } as never,
        ],
      };

      presenter.present(result);

      expect(presenter.responseModel.penalties).toHaveLength(2);
      expect(presenter.responseModel.driverMap).toEqual({
        'driver-1': 'Driver One',
        'driver-2': 'Driver Two',
      });
    });

    it('should handle empty penalties', () => {
      const result: GetRacePenaltiesResult = {
        penalties: [],
        drivers: [],
      };

      presenter.present(result);

      expect(presenter.responseModel).toEqual({
        penalties: [],
        driverMap: {},
      });
    });

    it('should handle penalties with undefined value', () => {
      const result: GetRacePenaltiesResult = {
        penalties: [
          {
            id: 'penalty-1',
            driverId: 'driver-1',
            type: 'disqualification',
            value: undefined,
            reason: 'Reason',
            issuedBy: 'steward-1',
            issuedAt: new Date('2024-01-01T10:00:00Z'),
          } as never,
        ],
        drivers: [{ id: 'driver-1', name: { toString: () => 'Driver One' } } as never],
      };

      presenter.present(result);

      expect(presenter.responseModel.penalties[0]?.value).toBe(0);
    });
  });

  describe('reset', () => {
    it('should clear the model', () => {
      presenter.present({
        penalties: [{ id: 'p1', driverId: 'd1', type: 't', value: 1, reason: 'r', issuedBy: 's1', issuedAt: new Date() } as never],
        drivers: [{ id: 'd1', name: { toString: () => 'D1' } } as never],
      });
      expect(presenter.responseModel).toBeDefined();

      presenter.reset();
      expect(() => presenter.responseModel).toThrow('Presenter not presented');
    });
  });

  describe('responseModel', () => {
    it('should throw error when accessed before present()', () => {
      expect(() => presenter.responseModel).toThrow('Presenter not presented');
    });
  });

  describe('viewModel', () => {
    it('should return same as responseModel', () => {
      const result: GetRacePenaltiesResult = {
        penalties: [{ id: 'p1', driverId: 'd1', type: 't', value: 1, reason: 'r', issuedBy: 's1', issuedAt: new Date() } as never],
        drivers: [{ id: 'd1', name: { toString: () => 'D1' } } as never],
      };

      presenter.present(result);

      expect(presenter.viewModel).toEqual(presenter.responseModel);
    });
  });
});