import { Injectable, Inject } from '@nestjs/common';
import { DriversLeaderboardDTO } from './dtos/DriversLeaderboardDTO';
import { DriverStatsDTO } from './dtos/DriverStatsDTO';
import { CompleteOnboardingInputDTO } from './dtos/CompleteOnboardingInputDTO';
import { CompleteOnboardingOutputDTO } from './dtos/CompleteOnboardingOutputDTO';
import { GetDriverRegistrationStatusQueryDTO } from './dtos/GetDriverRegistrationStatusQueryDTO';
import { DriverRegistrationStatusDTO } from './dtos/DriverRegistrationStatusDTO';

// Use cases
import { GetDriversLeaderboardUseCase } from '@core/racing/application/use-cases/GetDriversLeaderboardUseCase';
import { GetTotalDriversUseCase } from '@core/racing/application/use-cases/GetTotalDriversUseCase';
import { CompleteDriverOnboardingUseCase } from '@core/racing/application/use-cases/CompleteDriverOnboardingUseCase';
import { IsDriverRegisteredForRaceUseCase } from '@core/racing/application/use-cases/IsDriverRegisteredForRaceUseCase';

// Presenters
import { DriversLeaderboardPresenter } from './presenters/DriversLeaderboardPresenter';
import { DriverStatsPresenter } from './presenters/DriverStatsPresenter';
import { CompleteOnboardingPresenter } from './presenters/CompleteOnboardingPresenter';
import { DriverRegistrationStatusPresenter } from './presenters/DriverRegistrationStatusPresenter';

// Tokens
import { GET_DRIVERS_LEADERBOARD_USE_CASE_TOKEN, GET_TOTAL_DRIVERS_USE_CASE_TOKEN, COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN, IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN, UPDATE_DRIVER_PROFILE_USE_CASE_TOKEN, LOGGER_TOKEN, DRIVER_REPOSITORY_TOKEN } from './DriverProviders';
import type { Logger } from '@core/shared/application';
import { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository';
import { UpdateDriverProfileUseCase } from '@core/racing/application/use-cases/UpdateDriverProfileUseCase';

@Injectable()
export class DriverService {
  constructor(
    @Inject(GET_DRIVERS_LEADERBOARD_USE_CASE_TOKEN) private readonly getDriversLeaderboardUseCase: GetDriversLeaderboardUseCase,
    @Inject(GET_TOTAL_DRIVERS_USE_CASE_TOKEN) private readonly getTotalDriversUseCase: GetTotalDriversUseCase,
    @Inject(COMPLETE_DRIVER_ONBOARDING_USE_CASE_TOKEN) private readonly completeDriverOnboardingUseCase: CompleteDriverOnboardingUseCase,
    @Inject(IS_DRIVER_REGISTERED_FOR_RACE_USE_CASE_TOKEN) private readonly isDriverRegisteredForRaceUseCase: IsDriverRegisteredForRaceUseCase,
    @Inject(UPDATE_DRIVER_PROFILE_USE_CASE_TOKEN) private readonly updateDriverProfileUseCase: UpdateDriverProfileUseCase,
    @Inject(DRIVER_REPOSITORY_TOKEN) private readonly driverRepository: IDriverRepository,
    @Inject(LOGGER_TOKEN) private readonly logger: Logger,
  ) {}

  async getDriversLeaderboard(): Promise<DriversLeaderboardDTO> {
    this.logger.debug('[DriverService] Fetching drivers leaderboard.');

    const presenter = new DriversLeaderboardPresenter();
    await this.getDriversLeaderboardUseCase.execute(undefined, presenter);
    return presenter.viewModel;
  }

  async getTotalDrivers(): Promise<DriverStatsDTO> {
    this.logger.debug('[DriverService] Fetching total drivers count.');

    const presenter = new DriverStatsPresenter();
    await this.getTotalDriversUseCase.execute(undefined, presenter);
    return presenter.viewModel;
  }

  async completeOnboarding(userId: string, input: CompleteOnboardingInputDTO): Promise<CompleteOnboardingOutputDTO> {
    this.logger.debug('Completing onboarding for user:', userId);

    const presenter = new CompleteOnboardingPresenter();
    await this.completeDriverOnboardingUseCase.execute({
      userId,
      firstName: input.firstName,
      lastName: input.lastName,
      displayName: input.displayName,
      country: input.country,
      timezone: input.timezone,
      bio: input.bio,
    }, presenter);
    return presenter.viewModel;
  }

  async getDriverRegistrationStatus(query: GetDriverRegistrationStatusQueryDTO): Promise<DriverRegistrationStatusDTO> {
    this.logger.debug('Checking driver registration status:', query);

    const presenter = new DriverRegistrationStatusPresenter();
    await this.isDriverRegisteredForRaceUseCase.execute({ raceId: query.raceId, driverId: query.driverId }, presenter);
    return presenter.viewModel;
  }

  async getCurrentDriver(userId: string): Promise<DriverDTO | null> {
    this.logger.debug(`[DriverService] Fetching current driver for userId: ${userId}`);

    const driver = await this.driverRepository.findById(userId);
    if (!driver) {
      return null;
    }

    return {
      id: driver.id,
      name: driver.name.value,
    };
  }

  async updateDriverProfile(driverId: string, bio?: string, country?: string): Promise<DriverDTO | null> {
    this.logger.debug(`[DriverService] Updating driver profile for driverId: ${driverId}`);

    const result = await this.updateDriverProfileUseCase.execute({ driverId, bio, country });
    if (result.isErr()) {
      this.logger.error(`Failed to update driver profile: ${result.error.code}`);
      return null;
    }

    return result.value;
  }
}
