import { describe, it, expect } from 'vitest';
import { RaceResultsDetailViewModel } from './RaceResultsDetailViewModel';
import { RaceResultViewModel } from './RaceResultViewModel';
import type { RaceResultsDetailDTO } from '../types/generated/RaceResultsDetailDTO';
import type { RaceResultDTO } from '../types/generated/RaceResultDTO';

const createResult = (overrides: Partial<RaceResultDTO> = {}): RaceResultDTO => ({
  driverId: 'driver-1',
  driverName: 'Driver One',
  avatarUrl: 'https://example.com/avatar.jpg',
  position: 2,
  startPosition: 3,
  incidents: 1,
  fastestLap: 90.5,
  positionChange: 1,
  isPodium: true,
  isClean: true,
  ...overrides,
});

const createDto = (overrides: Partial<RaceResultsDetailDTO & { results?: RaceResultDTO[] }> = {}): RaceResultsDetailDTO & { results?: RaceResultDTO[] } => ({
  raceId: 'race-1',
  track: 'Spa',
  ...overrides,
});

describe('RaceResultsDetailViewModel', () => {
  it('maps basic fields and wraps results into view models', () => {
    const dto = createDto({
      results: [createResult({ driverId: 'driver-1' }), createResult({ driverId: 'driver-2' })],
    });

    const viewModel = new RaceResultsDetailViewModel(dto, 'driver-1');

    expect(viewModel.raceId).toBe('race-1');
    expect(viewModel.track).toBe('Spa');
    expect(viewModel.results).toHaveLength(2);
    expect(viewModel.results[0]).toBeInstanceOf(RaceResultViewModel);
  });

  it('sorts results by position', () => {
    const dto = createDto({
      results: [
        createResult({ driverId: 'driver-1', position: 3 }),
        createResult({ driverId: 'driver-2', position: 1 }),
        createResult({ driverId: 'driver-3', position: 2 }),
      ],
    });

    const viewModel = new RaceResultsDetailViewModel(dto, 'driver-1');

    const byPosition = viewModel.resultsByPosition;

    expect(byPosition.map(r => r.position)).toEqual([1, 2, 3]);
  });

  it('sorts results by fastest lap', () => {
    const dto = createDto({
      results: [
        createResult({ driverId: 'driver-1', fastestLap: 95 }),
        createResult({ driverId: 'driver-2', fastestLap: 90 }),
        createResult({ driverId: 'driver-3', fastestLap: 100 }),
      ],
    });

    const viewModel = new RaceResultsDetailViewModel(dto, 'driver-1');

    const byLap = viewModel.resultsByFastestLap;

    expect(byLap.map(r => r.fastestLap)).toEqual([90, 95, 100]);
  });

  it('filters clean drivers', () => {
    const dto = createDto({
      results: [
        createResult({ driverId: 'driver-1', isClean: true }),
        createResult({ driverId: 'driver-2', isClean: false }),
      ],
    });

    const viewModel = new RaceResultsDetailViewModel(dto, 'driver-1');

    const clean = viewModel.cleanDrivers;

    expect(clean).toHaveLength(1);
    expect(clean[0].driverId).toBe('driver-1');
  });

  it('finds current user result by driver id', () => {
    const dto = createDto({
      results: [
        createResult({ driverId: 'driver-1' }),
        createResult({ driverId: 'driver-2' }),
      ],
    });

    const viewModel = new RaceResultsDetailViewModel(dto, 'driver-2');

    expect(viewModel.currentUserResult?.driverId).toBe('driver-2');
  });

  it('computes stats for total drivers, clean rate and average incidents', () => {
    const dto = createDto({
      results: [
        createResult({ driverId: 'driver-1', isClean: true, incidents: 0 }),
        createResult({ driverId: 'driver-2', isClean: false, incidents: 4 }),
      ],
    });

    const viewModel = new RaceResultsDetailViewModel(dto, 'driver-1');

    const stats = viewModel.stats;

    expect(stats.totalDrivers).toBe(2);
    expect(stats.cleanRate).toBeCloseTo(50);
    expect(stats.averageIncidents).toBeCloseTo(2);
  });

  it('returns zeroed stats when there are no results', () => {
    const dto = createDto({ results: [] });

    const viewModel = new RaceResultsDetailViewModel(dto, 'driver-1');

    const stats = viewModel.stats;

    expect(stats.totalDrivers).toBe(0);
    expect(stats.cleanRate).toBe(0);
    expect(stats.averageIncidents).toBe(0);
  });
});
