import { describe, expect, it, vi } from 'vitest';
import { Result } from '@core/shared/application/Result';
import { DriverService } from './DriverService';

describe('DriverService', () => {
  const logger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() };

  it('getDriversLeaderboard executes use case and returns presenter model', async () => {
    const getDriversLeaderboardUseCase = { execute: vi.fn(async () => Result.ok(undefined)) };
    const driversLeaderboardPresenter = {
      setMediaResolver: vi.fn(),
      setBaseUrl: vi.fn(),
      present: vi.fn(),
      getResponseModel: vi.fn(() => ({ items: [] }))
    };
    const driverPresenter = {
      setMediaResolver: vi.fn(),
      setBaseUrl: vi.fn(),
      present: vi.fn(),
      getResponseModel: vi.fn(() => null)
    };

    const service = new DriverService(
      getDriversLeaderboardUseCase as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { findById: vi.fn() } as any,
      logger as any,
      driversLeaderboardPresenter as any,
      { getResponseModel: vi.fn(() => ({ totalDrivers: 0 })) } as any,
      { getResponseModel: vi.fn(() => ({ success: true })) } as any,
      { getResponseModel: vi.fn(() => ({ isRegistered: false })) } as any,
      driverPresenter as any,
      { getResponseModel: vi.fn(() => ({ profile: {} })) } as any,
    );

    await expect(service.getDriversLeaderboard()).resolves.toEqual({ items: [] });
    expect(getDriversLeaderboardUseCase.execute).toHaveBeenCalledWith({});
    expect(driversLeaderboardPresenter.getResponseModel).toHaveBeenCalled();
  });

  it('getTotalDrivers executes use case and returns presenter model', async () => {
    const getTotalDriversUseCase = { execute: vi.fn(async () => Result.ok(undefined)) };
    const driverStatsPresenter = { getResponseModel: vi.fn(() => ({ totalDrivers: 123 })) };
    const driverPresenter = {
      setMediaResolver: vi.fn(),
      setBaseUrl: vi.fn(),
      present: vi.fn(),
      getResponseModel: vi.fn(() => null)
    };

    const service = new DriverService(
      { execute: vi.fn() } as any,
      getTotalDriversUseCase as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { findById: vi.fn() } as any,
      logger as any,
      { getResponseModel: vi.fn(() => ({ items: [] })) } as any,
      driverStatsPresenter as any,
      { getResponseModel: vi.fn(() => ({ success: true })) } as any,
      { getResponseModel: vi.fn(() => ({ isRegistered: false })) } as any,
      driverPresenter as any,
      { getResponseModel: vi.fn(() => ({ profile: {} })) } as any,
    );

    await expect(service.getTotalDrivers()).resolves.toEqual({ totalDrivers: 123 });
    expect(getTotalDriversUseCase.execute).toHaveBeenCalledWith({});
    expect(driverStatsPresenter.getResponseModel).toHaveBeenCalled();
  });

  it('completeOnboarding passes optional bio only when provided', async () => {
    const completeDriverOnboardingUseCase = { execute: vi.fn(async () => Result.ok(undefined)) };
    const driverPresenter = {
      setMediaResolver: vi.fn(),
      setBaseUrl: vi.fn(),
      present: vi.fn(),
      getResponseModel: vi.fn(() => null)
    };

    const service = new DriverService(
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      completeDriverOnboardingUseCase as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { findById: vi.fn() } as any,
      logger as any,
      { getResponseModel: vi.fn(() => ({ items: [] })) } as any,
      { getResponseModel: vi.fn(() => ({ totalDrivers: 0 })) } as any,
      { getResponseModel: vi.fn(() => ({ success: true })) } as any,
      { getResponseModel: vi.fn(() => ({ isRegistered: false })) } as any,
      driverPresenter as any,
      { getResponseModel: vi.fn(() => ({ profile: {} })) } as any,
    );

    await service.completeOnboarding('u1', {
      firstName: 'F',
      lastName: 'L',
      displayName: 'D',
      country: 'DE',
    } as any);

    expect(completeDriverOnboardingUseCase.execute).toHaveBeenCalledWith({
      userId: 'u1',
      firstName: 'F',
      lastName: 'L',
      displayName: 'D',
      country: 'DE',
    });

    completeDriverOnboardingUseCase.execute.mockClear();

    await service.completeOnboarding('u1', {
      firstName: 'F',
      lastName: 'L',
      displayName: 'D',
      country: 'DE',
      bio: 'bio',
    } as any);

    expect(completeDriverOnboardingUseCase.execute).toHaveBeenCalledWith({
      userId: 'u1',
      firstName: 'F',
      lastName: 'L',
      displayName: 'D',
      country: 'DE',
      bio: 'bio',
    });
  });

  it('getDriverRegistrationStatus passes raceId and driverId and returns presenter model', async () => {
    const isDriverRegisteredForRaceUseCase = { execute: vi.fn(async () => Result.ok(undefined)) };
    const driverRegistrationStatusPresenter = { getResponseModel: vi.fn(() => ({ isRegistered: true })) };
    const driverPresenter = {
      setMediaResolver: vi.fn(),
      setBaseUrl: vi.fn(),
      present: vi.fn(),
      getResponseModel: vi.fn(() => null)
    };

    const service = new DriverService(
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      isDriverRegisteredForRaceUseCase as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { findById: vi.fn() } as any,
      logger as any,
      { getResponseModel: vi.fn(() => ({ items: [] })) } as any,
      { getResponseModel: vi.fn(() => ({ totalDrivers: 0 })) } as any,
      { getResponseModel: vi.fn(() => ({ success: true })) } as any,
      driverRegistrationStatusPresenter as any,
      driverPresenter as any,
      { getResponseModel: vi.fn(() => ({ profile: {} })) } as any,
    );

    await expect(
      service.getDriverRegistrationStatus({ raceId: 'r1', driverId: 'd1' } as any),
    ).resolves.toEqual({ isRegistered: true });

    expect(isDriverRegisteredForRaceUseCase.execute).toHaveBeenCalledWith({ raceId: 'r1', driverId: 'd1' });
    expect(driverRegistrationStatusPresenter.getResponseModel).toHaveBeenCalled();
  });

  it('getCurrentDriver calls repository and returns presenter model', async () => {
    const driverRepository = { findById: vi.fn(async () => null) };
    const driverPresenter = {
      setMediaResolver: vi.fn(),
      setBaseUrl: vi.fn(),
      present: vi.fn(),
      getResponseModel: vi.fn(() => null)
    };

    const service = new DriverService(
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      driverRepository as any,
      logger as any,
      { getResponseModel: vi.fn(() => ({ items: [] })) } as any,
      { getResponseModel: vi.fn(() => ({ totalDrivers: 0 })) } as any,
      { getResponseModel: vi.fn(() => ({ success: true })) } as any,
      { getResponseModel: vi.fn(() => ({ isRegistered: false })) } as any,
      driverPresenter as any,
      { getResponseModel: vi.fn(() => ({ profile: {} })) } as any,
    );

    await expect(service.getCurrentDriver('u1')).resolves.toBeNull();
    expect(driverRepository.findById).toHaveBeenCalledWith('u1');
    expect(driverPresenter.getResponseModel).toHaveBeenCalled();
  });

  it('updateDriverProfile builds optional input and returns presenter model', async () => {
    const updateDriverProfileUseCase = { execute: vi.fn(async () => {}) };
    const driverPresenter = {
      setMediaResolver: vi.fn(),
      setBaseUrl: vi.fn(),
      present: vi.fn(),
      getResponseModel: vi.fn(() => ({ driver: { id: 'd1' } }))
    };

    const service = new DriverService(
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      updateDriverProfileUseCase as any,
      { execute: vi.fn() } as any,
      { findById: vi.fn() } as any,
      logger as any,
      { getResponseModel: vi.fn(() => ({ items: [] })) } as any,
      { getResponseModel: vi.fn(() => ({ totalDrivers: 0 })) } as any,
      { getResponseModel: vi.fn(() => ({ success: true })) } as any,
      { getResponseModel: vi.fn(() => ({ isRegistered: false })) } as any,
      driverPresenter as any,
      { getResponseModel: vi.fn(() => ({ profile: {} })) } as any,
    );

    await service.updateDriverProfile('d1');
    expect(updateDriverProfileUseCase.execute).toHaveBeenCalledWith({ driverId: 'd1' });

    updateDriverProfileUseCase.execute.mockClear();

    await service.updateDriverProfile('d1', 'bio');
    expect(updateDriverProfileUseCase.execute).toHaveBeenCalledWith({ driverId: 'd1', bio: 'bio' });

    updateDriverProfileUseCase.execute.mockClear();

    await service.updateDriverProfile('d1', undefined, 'DE');
    expect(updateDriverProfileUseCase.execute).toHaveBeenCalledWith({ driverId: 'd1', country: 'DE' });

    updateDriverProfileUseCase.execute.mockClear();

    await service.updateDriverProfile('d1', 'bio', 'DE');
    expect(updateDriverProfileUseCase.execute).toHaveBeenCalledWith({ driverId: 'd1', bio: 'bio', country: 'DE' });

    expect(driverPresenter.getResponseModel).toHaveBeenCalled();
  });

  it('getDriver calls repository and returns presenter model', async () => {
    const driverRepository = { findById: vi.fn(async () => null) };
    const driverPresenter = {
      setMediaResolver: vi.fn(),
      setBaseUrl: vi.fn(),
      present: vi.fn(),
      getResponseModel: vi.fn(() => ({ driver: null }))
    };

    const service = new DriverService(
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      driverRepository as any,
      logger as any,
      { getResponseModel: vi.fn(() => ({ items: [] })) } as any,
      { getResponseModel: vi.fn(() => ({ totalDrivers: 0 })) } as any,
      { getResponseModel: vi.fn(() => ({ success: true })) } as any,
      { getResponseModel: vi.fn(() => ({ isRegistered: false })) } as any,
      driverPresenter as any,
      { getResponseModel: vi.fn(() => ({ profile: {} })) } as any,
    );

    await expect(service.getDriver('d1')).resolves.toEqual({ driver: null });
    expect(driverRepository.findById).toHaveBeenCalledWith('d1');
    expect(driverPresenter.getResponseModel).toHaveBeenCalled();
  });

  it('getDriverProfile executes use case and returns presenter model', async () => {
    const getProfileOverviewUseCase = { execute: vi.fn(async () => Result.ok(undefined)) };
    const driverProfilePresenter = {
      setMediaResolver: vi.fn(),
      setBaseUrl: vi.fn(),
      getResponseModel: vi.fn(() => ({ profile: { id: 'd1' } }))
    };
    const driverPresenter = {
      setMediaResolver: vi.fn(),
      setBaseUrl: vi.fn(),
      present: vi.fn(),
      getResponseModel: vi.fn(() => null)
    };

    const service = new DriverService(
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      { execute: vi.fn() } as any,
      getProfileOverviewUseCase as any,
      { findById: vi.fn() } as any,
      logger as any,
      { getResponseModel: vi.fn(() => ({ items: [] })) } as any,
      { getResponseModel: vi.fn(() => ({ totalDrivers: 0 })) } as any,
      { getResponseModel: vi.fn(() => ({ success: true })) } as any,
      { getResponseModel: vi.fn(() => ({ isRegistered: false })) } as any,
      driverPresenter as any,
      driverProfilePresenter as any,
    );

    await expect(service.getDriverProfile('d1')).resolves.toEqual({ profile: { id: 'd1' } });
    expect(getProfileOverviewUseCase.execute).toHaveBeenCalledWith({ driverId: 'd1' });
    expect(driverProfilePresenter.getResponseModel).toHaveBeenCalled();
  });
});