import { describe, it, expect, vi } from 'vitest';
import { SendPerformanceSummaryUseCase } from './SendPerformanceSummaryUseCase';
import type { INotificationService } from '../../../notifications/application/ports/INotificationService';
import type { IRaceEventRepository } from '../../domain/repositories/IRaceEventRepository';
import type { IResultRepository } from '../../domain/repositories/IResultRepository';
import type { MainRaceCompletedEvent } from '../../domain/events/MainRaceCompleted';

describe('SendPerformanceSummaryUseCase', () => {
  it('sends performance summary notifications to all participating drivers', async () => {
    const mockNotificationService = {
      sendNotification: vi.fn(),
    } as unknown as INotificationService;

    const mockRaceEvent = {
      id: 'race-1',
      name: 'Test Race',
      getMainRaceSession: vi.fn().mockReturnValue({ id: 'session-1' }),
    };

    const mockRaceEventRepository = {
      findById: vi.fn().mockResolvedValue(mockRaceEvent),
    } as unknown as IRaceEventRepository;

    const mockResults = [
      {
        driverId: 'driver-1',
        position: 1,
        incidents: 0,
        getPositionChange: vi.fn().mockReturnValue(2),
      },
      {
        driverId: 'driver-2',
        position: 2,
        incidents: 1,
        getPositionChange: vi.fn().mockReturnValue(-1),
      },
    ];

    const mockResultRepository = {
      findByRaceId: vi.fn().mockResolvedValue(mockResults),
    } as unknown as IResultRepository;

    const useCase = new SendPerformanceSummaryUseCase(
      mockNotificationService,
      mockRaceEventRepository,
      mockResultRepository,
    );

    const event: MainRaceCompletedEvent = {
      eventType: 'MainRaceCompleted',
      aggregateId: 'race-1',
      occurredAt: new Date(),
      eventData: {
        raceEventId: 'race-1',
        sessionId: 'session-1',
        seasonId: 'season-1',
        leagueId: 'league-1',
        driverIds: ['driver-1', 'driver-2'],
        completedAt: new Date(),
      },
    };

    const result = await useCase.execute(event);

    expect(result.isOk()).toBe(true);
    expect(mockRaceEventRepository.findById).toHaveBeenCalledWith('race-1');
    expect(mockResultRepository.findByRaceId).toHaveBeenCalledWith('session-1');
    expect(mockNotificationService.sendNotification).toHaveBeenCalledTimes(2);

    // Check first notification
    expect(mockNotificationService.sendNotification).toHaveBeenCalledWith(
      expect.objectContaining({
        recipientId: 'driver-1',
        type: 'race_performance_summary',
        title: 'Race Complete: Test Race',
        body: expect.stringContaining('You finished P1 (+2 positions). Clean race! Provisional +35 rating.'),
        data: expect.objectContaining({
          raceEventId: 'race-1',
          sessionId: 'session-1',
          leagueId: 'league-1',
          position: 1,
          positionChange: 2,
          incidents: 0,
          provisionalRatingChange: 35,
        }),
      }),
    );

    // Check second notification
    expect(mockNotificationService.sendNotification).toHaveBeenCalledWith(
      expect.objectContaining({
        recipientId: 'driver-2',
        type: 'race_performance_summary',
        title: 'Race Complete: Test Race',
        body: expect.stringContaining('You finished P2 (-1 positions). 1 incident Provisional +20 rating.'),
        data: expect.objectContaining({
          position: 2,
          positionChange: -1,
          incidents: 1,
          provisionalRatingChange: 20,
        }),
      }),
    );
  });

  it('skips sending notifications if race event not found', async () => {
    const mockNotificationService = {
      sendNotification: vi.fn(),
    } as unknown as INotificationService;

    const mockRaceEventRepository = {
      findById: vi.fn().mockResolvedValue(null),
    } as unknown as IRaceEventRepository;

    const mockResultRepository = {
      findByRaceId: vi.fn(),
    } as unknown as IResultRepository;

    const useCase = new SendPerformanceSummaryUseCase(
      mockNotificationService,
      mockRaceEventRepository,
      mockResultRepository,
    );

    const event: MainRaceCompletedEvent = {
      eventType: 'MainRaceCompleted',
      aggregateId: 'race-1',
      occurredAt: new Date(),
      eventData: {
        raceEventId: 'race-1',
        sessionId: 'session-1',
        seasonId: 'season-1',
        leagueId: 'league-1',
        driverIds: ['driver-1'],
        completedAt: new Date(),
      },
    };

    const result = await useCase.execute(event);

    expect(result.isOk()).toBe(true);
    expect(mockNotificationService.sendNotification).not.toHaveBeenCalled();
  });
});