import { Injectable, Inject } from '@nestjs/common';
import { AllLeaguesWithCapacityDTO } from './dtos/AllLeaguesWithCapacityDTO';
import { LeagueStatsDTO } from './dtos/LeagueStatsDTO';
import { LeagueJoinRequestDTO } from './dtos/LeagueJoinRequestDTO';
import { ApproveJoinRequestInputDTO } from './dtos/ApproveJoinRequestInputDTO';
import { ApproveJoinRequestOutputDTO } from './dtos/ApproveJoinRequestOutputDTO';
import { RejectJoinRequestInputDTO } from './dtos/RejectJoinRequestInputDTO';
import { RejectJoinRequestOutputDTO } from './dtos/RejectJoinRequestOutputDTO';
import { LeagueAdminPermissionsDTO } from './dtos/LeagueAdminPermissionsDTO';
import { RemoveLeagueMemberInputDTO } from './dtos/RemoveLeagueMemberInputDTO';
import { RemoveLeagueMemberOutputDTO } from './dtos/RemoveLeagueMemberOutputDTO';
import { UpdateLeagueMemberRoleInputDTO } from './dtos/UpdateLeagueMemberRoleInputDTO';
import { UpdateLeagueMemberRoleOutputDTO } from './dtos/UpdateLeagueMemberRoleOutputDTO';
import { LeagueOwnerSummaryDTO } from './dtos/LeagueOwnerSummaryDTO';
import { LeagueConfigFormModelDTO } from './dtos/LeagueConfigFormModelDTO';
import { LeagueAdminProtestsDTO } from './dtos/LeagueAdminProtestsDTO';
import { LeagueSeasonSummaryDTO } from './dtos/LeagueSeasonSummaryDTO';
import { GetLeagueAdminPermissionsInputDTO } from './dtos/GetLeagueAdminPermissionsInputDTO';
import { GetLeagueProtestsQueryDTO } from './dtos/GetLeagueProtestsQueryDTO';
import { GetLeagueSeasonsQueryDTO } from './dtos/GetLeagueSeasonsQueryDTO';
import { GetLeagueAdminConfigQueryDTO } from './dtos/GetLeagueAdminConfigQueryDTO';
import { GetLeagueOwnerSummaryQueryDTO } from './dtos/GetLeagueOwnerSummaryQueryDTO';
import { LeagueMembershipsDTO } from './dtos/LeagueMembershipsDTO';
import { LeagueStandingsDTO } from './dtos/LeagueStandingsDTO';
import { LeagueScheduleDTO } from './dtos/LeagueScheduleDTO';
import { LeagueStatsDTO } from './dtos/LeagueStatsDTO';
import { LeagueAdminDTO } from './dtos/LeagueAdminDTO';
import { CreateLeagueInputDTO } from './dtos/CreateLeagueInputDTO';
import { CreateLeagueOutputDTO } from './dtos/CreateLeagueOutputDTO';

// Core imports
import type { Logger } from '@core/shared/application/Logger';

// Use cases
import { GetAllLeaguesWithCapacityUseCase } from '@core/racing/application/use-cases/GetAllLeaguesWithCapacityUseCase';
import { GetLeagueStandingsUseCase } from '@core/racing/application/use-cases/GetLeagueStandingsUseCase';
import { GetLeagueStatsUseCase } from '@core/racing/application/use-cases/GetLeagueStatsUseCase';
import { GetLeagueFullConfigUseCase } from '@core/racing/application/use-cases/GetLeagueFullConfigUseCase';
import { GetLeagueScoringConfigUseCase } from '@core/racing/application/use-cases/GetLeagueScoringConfigUseCase';
import { ListLeagueScoringPresetsUseCase } from '@core/racing/application/use-cases/ListLeagueScoringPresetsUseCase';
import { JoinLeagueUseCase } from '@core/racing/application/use-cases/JoinLeagueUseCase';
import { TransferLeagueOwnershipUseCase } from '@core/racing/application/use-cases/TransferLeagueOwnershipUseCase';
import { CreateLeagueWithSeasonAndScoringUseCase } from '@core/racing/application/use-cases/CreateLeagueWithSeasonAndScoringUseCase';
import { GetRaceProtestsUseCase } from '@core/racing/application/use-cases/GetRaceProtestsUseCase';
import { GetTotalLeaguesUseCase } from '@core/racing/application/use-cases/GetTotalLeaguesUseCase';
import { GetLeagueJoinRequestsUseCase } from '@core/racing/application/use-cases/GetLeagueJoinRequestsUseCase';
import { ApproveLeagueJoinRequestUseCase } from '@core/racing/application/use-cases/ApproveLeagueJoinRequestUseCase';
import { RejectLeagueJoinRequestUseCase } from '@core/racing/application/use-cases/RejectLeagueJoinRequestUseCase';
import { RemoveLeagueMemberUseCase } from '@core/racing/application/use-cases/RemoveLeagueMemberUseCase';
import { UpdateLeagueMemberRoleUseCase } from '@core/racing/application/use-cases/UpdateLeagueMemberRoleUseCase';
import { GetLeagueOwnerSummaryUseCase } from '@core/racing/application/use-cases/GetLeagueOwnerSummaryUseCase';
import { GetLeagueProtestsUseCase } from '@core/racing/application/use-cases/GetLeagueProtestsUseCase';
import { GetLeagueSeasonsUseCase } from '@core/racing/application/use-cases/GetLeagueSeasonsUseCase';
import { GetLeagueMembershipsUseCase } from '@core/racing/application/use-cases/GetLeagueMembershipsUseCase';
import { GetLeagueScheduleUseCase } from '@core/racing/application/use-cases/GetLeagueScheduleUseCase';
import { GetLeagueAdminPermissionsUseCase } from '@core/racing/application/use-cases/GetLeagueAdminPermissionsUseCase';

// API Presenters
import { LeagueStandingsPresenter } from './presenters/LeagueStandingsPresenter';
import { AllLeaguesWithCapacityPresenter } from './presenters/AllLeaguesWithCapacityPresenter';
import { LeagueScoringConfigPresenter } from './presenters/LeagueScoringConfigPresenter';
import { LeagueScoringPresetsPresenter } from './presenters/LeagueScoringPresetsPresenter';
import { LeagueJoinRequestsPresenter } from './presenters/LeagueJoinRequestsPresenter';
import { ApproveLeagueJoinRequestPresenter } from './presenters/ApproveLeagueJoinRequestPresenter';
import { RejectLeagueJoinRequestPresenter } from './presenters/RejectLeagueJoinRequestPresenter';
import { RemoveLeagueMemberPresenter } from './presenters/RemoveLeagueMemberPresenter';
import { UpdateLeagueMemberRolePresenter } from './presenters/UpdateLeagueMemberRolePresenter';
import { GetLeagueOwnerSummaryPresenter } from './presenters/GetLeagueOwnerSummaryPresenter';
import { GetLeagueProtestsPresenter } from './presenters/GetLeagueProtestsPresenter';
import { GetLeagueSeasonsPresenter } from './presenters/GetLeagueSeasonsPresenter';
import { GetLeagueMembershipsPresenter } from './presenters/GetLeagueMembershipsPresenter';
import { LeagueSchedulePresenter } from './presenters/LeagueSchedulePresenter';
import { TotalLeaguesPresenter } from './presenters/TotalLeaguesPresenter';
import { LeagueConfigPresenter } from './presenters/LeagueConfigPresenter';
import { LeagueStatsPresenter } from './presenters/LeagueStatsPresenter';
import { GetLeagueAdminPermissionsPresenter } from './presenters/GetLeagueAdminPermissionsPresenter';

// Tokens
import { LOGGER_TOKEN } from './LeagueProviders';

@Injectable()
export class LeagueService {
  constructor(
    private readonly getAllLeaguesWithCapacityUseCase: GetAllLeaguesWithCapacityUseCase,
    private readonly getLeagueStandingsUseCase: GetLeagueStandingsUseCase,
    private readonly getLeagueStatsUseCase: GetLeagueStatsUseCase,
    private readonly getLeagueFullConfigUseCase: GetLeagueFullConfigUseCase,
    private readonly getLeagueScoringConfigUseCase: GetLeagueScoringConfigUseCase,
    private readonly listLeagueScoringPresetsUseCase: ListLeagueScoringPresetsUseCase,
    private readonly joinLeagueUseCase: JoinLeagueUseCase,
    private readonly transferLeagueOwnershipUseCase: TransferLeagueOwnershipUseCase,
    private readonly createLeagueWithSeasonAndScoringUseCase: CreateLeagueWithSeasonAndScoringUseCase,
    private readonly getRaceProtestsUseCase: GetRaceProtestsUseCase,
    private readonly getTotalLeaguesUseCase: GetTotalLeaguesUseCase,
    private readonly getLeagueJoinRequestsUseCase: GetLeagueJoinRequestsUseCase,
    private readonly approveLeagueJoinRequestUseCase: ApproveLeagueJoinRequestUseCase,
    private readonly rejectLeagueJoinRequestUseCase: RejectLeagueJoinRequestUseCase,
    private readonly removeLeagueMemberUseCase: RemoveLeagueMemberUseCase,
    private readonly updateLeagueMemberRoleUseCase: UpdateLeagueMemberRoleUseCase,
    private readonly getLeagueOwnerSummaryUseCase: GetLeagueOwnerSummaryUseCase,
    private readonly getLeagueProtestsUseCase: GetLeagueProtestsUseCase,
    private readonly getLeagueSeasonsUseCase: GetLeagueSeasonsUseCase,
    private readonly getLeagueMembershipsUseCase: GetLeagueMembershipsUseCase,
    private readonly getLeagueScheduleUseCase: GetLeagueScheduleUseCase,
    private readonly getLeagueAdminPermissionsUseCase: GetLeagueAdminPermissionsUseCase,
    @Inject(LOGGER_TOKEN) private readonly logger: Logger,
  ) {}

  async getAllLeaguesWithCapacity(): Promise<AllLeaguesWithCapacityViewModel> {
    this.logger.debug('[LeagueService] Fetching all leagues with capacity.');

    const presenter = new AllLeaguesWithCapacityPresenter();
    await this.getAllLeaguesWithCapacityUseCase.execute(undefined, presenter);
    return presenter.getViewModel()!;
  }

  async getTotalLeagues(): Promise<LeagueStatsDto> {
    this.logger.debug('[LeagueService] Fetching total leagues count.');
    const presenter = new TotalLeaguesPresenter();
    await this.getTotalLeaguesUseCase.execute({}, presenter);
    return presenter.getViewModel()!;
  }

  async getLeagueJoinRequests(leagueId: string): Promise<LeagueJoinRequestViewModel[]> {
    this.logger.debug(`[LeagueService] Fetching join requests for league: ${leagueId}.`);
    const presenter = new LeagueJoinRequestsPresenter();
    await this.getLeagueJoinRequestsUseCase.execute({ leagueId }, presenter);
    return presenter.getViewModel()!.joinRequests;
  }

  async approveLeagueJoinRequest(input: ApproveJoinRequestInput): Promise<ApproveJoinRequestOutput> {
    this.logger.debug('Approving join request:', input);
    const presenter = new ApproveLeagueJoinRequestPresenter();
    await this.approveLeagueJoinRequestUseCase.execute({ leagueId: input.leagueId, requestId: input.requestId }, presenter);
    return presenter.getViewModel()!;
  }

  async rejectLeagueJoinRequest(input: RejectJoinRequestInput): Promise<RejectJoinRequestOutput> {
    this.logger.debug('Rejecting join request:', input);
    const presenter = new RejectLeagueJoinRequestPresenter();
    await this.rejectLeagueJoinRequestUseCase.execute({ requestId: input.requestId }, presenter);
    return presenter.getViewModel()!;
  }

  async getLeagueAdminPermissions(query: GetLeagueAdminPermissionsInput): Promise<LeagueAdminPermissionsViewModel> {
    this.logger.debug('Getting league admin permissions', { query });
    const presenter = new GetLeagueAdminPermissionsPresenter();
    await this.getLeagueAdminPermissionsUseCase.execute(
      { leagueId: query.leagueId, performerDriverId: query.performerDriverId },
      presenter
    );
    return presenter.getViewModel()!;
  }

  async removeLeagueMember(input: RemoveLeagueMemberInput): Promise<RemoveLeagueMemberOutput> {
    this.logger.debug('Removing league member', { leagueId: input.leagueId, targetDriverId: input.targetDriverId });
    const presenter = new RemoveLeagueMemberPresenter();
    await this.removeLeagueMemberUseCase.execute({ leagueId: input.leagueId, targetDriverId: input.targetDriverId }, presenter);
    return presenter.getViewModel()!;
  }

  async updateLeagueMemberRole(input: UpdateLeagueMemberRoleInput): Promise<UpdateLeagueMemberRoleOutput> {
    this.logger.debug('Updating league member role', { leagueId: input.leagueId, targetDriverId: input.targetDriverId, newRole: input.newRole });
    const presenter = new UpdateLeagueMemberRolePresenter();
    await this.updateLeagueMemberRoleUseCase.execute({ leagueId: input.leagueId, targetDriverId: input.targetDriverId, newRole: input.newRole }, presenter);
    return presenter.getViewModel()!;
  }

  async getLeagueOwnerSummary(query: GetLeagueOwnerSummaryQuery): Promise<LeagueOwnerSummaryViewModel | null> {
    this.logger.debug('Getting league owner summary:', query);
    const presenter = new GetLeagueOwnerSummaryPresenter();
    await this.getLeagueOwnerSummaryUseCase.execute({ ownerId: query.ownerId }, presenter);
    return presenter.getViewModel()!.summary;
  }

  async getLeagueFullConfig(query: GetLeagueAdminConfigQuery): Promise<LeagueConfigFormModelDto | null> {
    this.logger.debug('Getting league full config', { query });

    const presenter = new LeagueConfigPresenter();
    try {
      await this.getLeagueFullConfigUseCase.execute({ leagueId: query.leagueId }, presenter);
      return presenter.viewModel;
    } catch (error) {
      this.logger.error('Error getting league full config', error instanceof Error ? error : new Error(String(error)));
      return null;
    }
  }

  async getLeagueProtests(query: GetLeagueProtestsQuery): Promise<LeagueAdminProtestsViewModel> {
    this.logger.debug('Getting league protests:', query);
    const presenter = new GetLeagueProtestsPresenter();
    await this.getLeagueProtestsUseCase.execute({ leagueId: query.leagueId }, presenter);
    return presenter.getViewModel()!;
  }

  async getLeagueSeasons(query: GetLeagueSeasonsQuery): Promise<LeagueSeasonSummaryViewModel[]> {
    this.logger.debug('Getting league seasons:', query);
    const presenter = new GetLeagueSeasonsPresenter();
    await this.getLeagueSeasonsUseCase.execute({ leagueId: query.leagueId }, presenter);
    return presenter.getViewModel()!.seasons;
  }

  async getLeagueMemberships(leagueId: string): Promise<LeagueMembershipsViewModel> {
    this.logger.debug('Getting league memberships', { leagueId });
    const presenter = new GetLeagueMembershipsPresenter();
    await this.getLeagueMembershipsUseCase.execute({ leagueId }, presenter);
    return presenter.apiViewModel!;
  }

  async getLeagueStandings(leagueId: string): Promise<LeagueStandingsViewModel> {
    this.logger.debug('Getting league standings', { leagueId });

    const presenter = new LeagueStandingsPresenter();
    await this.getLeagueStandingsUseCase.execute({ leagueId }, presenter);
    return presenter.getViewModel()!;
  }

  async getLeagueSchedule(leagueId: string): Promise<LeagueScheduleViewModel> {
    this.logger.debug('Getting league schedule', { leagueId });
    const presenter = new LeagueSchedulePresenter();
    await this.getLeagueScheduleUseCase.execute({ leagueId }, presenter);
    return presenter.getViewModel()!;
  }

  async getLeagueStats(leagueId: string): Promise<LeagueStatsViewModel> {
    this.logger.debug('Getting league stats', { leagueId });
    const presenter = new LeagueStatsPresenter();
    await this.getLeagueStatsUseCase.execute({ leagueId }, presenter);
    return presenter.getViewModel()!;
  }

  async getLeagueAdmin(leagueId: string): Promise<LeagueAdminViewModel> {
    this.logger.debug('Getting league admin data', { leagueId });
    // For now, we'll keep the orchestration in the service since it combines multiple use cases
    // TODO: Create a composite use case that handles all the admin data fetching
    const joinRequests = await this.getLeagueJoinRequests(leagueId);
    const config = await this.getLeagueFullConfig({ leagueId });
    const protests = await this.getLeagueProtests({ leagueId });
    const seasons = await this.getLeagueSeasons({ leagueId });

    // Get owner summary - we need the ownerId, so we use a simple approach for now
    // In a full implementation, we'd have a use case that gets league basic info
    const ownerSummary = config ? await this.getLeagueOwnerSummary({ ownerId: 'placeholder', leagueId }) : null;

    return {
      joinRequests,
      ownerSummary,
      config: { form: config },
      protests,
      seasons,
    };
  }

  async createLeague(input: CreateLeagueInput): Promise<CreateLeagueOutput> {
    this.logger.debug('Creating league', { input });
    const command = {
      name: input.name,
      description: input.description,
      ownerId: input.ownerId,
      visibility: 'unranked' as const,
      gameId: 'iracing', // Assume default
      maxDrivers: 32, // Default value
      enableDriverChampionship: true,
      enableTeamChampionship: false,
      enableNationsChampionship: false,
      enableTrophyChampionship: false,
    };
    const result = await this.createLeagueWithSeasonAndScoringUseCase.execute(command);
    return {
      leagueId: result.leagueId,
      success: true,
    };
  }

  async getLeagueScoringConfig(leagueId: string): Promise<LeagueScoringConfigViewModel | null> {
    this.logger.debug('Getting league scoring config', { leagueId });

    const presenter = new LeagueScoringConfigPresenter();
    try {
      const result = await this.getLeagueScoringConfigUseCase.execute({ leagueId });
      if (result.isErr()) {
        this.logger.error('Error getting league scoring config', result.error);
        return null;
      }
      await presenter.present(result.value);
      return presenter.getViewModel();
    } catch (error) {
      this.logger.error('Error getting league scoring config', error instanceof Error ? error : new Error(String(error)));
      return null;
    }
  }

  async listLeagueScoringPresets(): Promise<LeagueScoringPresetsViewModel> {
    this.logger.debug('Listing league scoring presets');

    const presenter = new LeagueScoringPresetsPresenter();
    await this.listLeagueScoringPresetsUseCase.execute(undefined, presenter);
    return presenter.getViewModel()!;
  }

  async joinLeague(leagueId: string, driverId: string): Promise<JoinLeagueOutput> {
    this.logger.debug('Joining league', { leagueId, driverId });

    const result = await this.joinLeagueUseCase.execute({ leagueId, driverId });
    if (result.isErr()) {
      return {
        success: false,
        error: result.error.code,
      };
    }
    return {
      success: true,
      membershipId: result.value.id,
    };
  }

  async transferLeagueOwnership(leagueId: string, currentOwnerId: string, newOwnerId: string): Promise<TransferLeagueOwnershipOutput> {
    this.logger.debug('Transferring league ownership', { leagueId, currentOwnerId, newOwnerId });

    const result = await this.transferLeagueOwnershipUseCase.execute({ leagueId, currentOwnerId, newOwnerId });
    if (result.isErr()) {
      return {
        success: false,
        error: result.error.code,
      };
    }
    return {
      success: true,
    };
  }
}
