import { Injectable, Inject } from '@nestjs/common';
import { CreateTeamInputDTO } from './dtos/CreateTeamInputDTO';
import { UpdateTeamInputDTO } from './dtos/UpdateTeamInputDTO';
import { GetAllTeamsOutputDTO } from './dtos/GetAllTeamsOutputDTO';
import { GetTeamDetailsOutputDTO } from './dtos/GetTeamDetailsOutputDTO';
import { GetTeamMembersOutputDTO } from './dtos/GetTeamMembersOutputDTO';
import { GetTeamJoinRequestsOutputDTO } from './dtos/GetTeamJoinRequestsOutputDTO';
import { CreateTeamOutputDTO } from './dtos/CreateTeamOutputDTO';
import { UpdateTeamOutputDTO } from './dtos/UpdateTeamOutputDTO';
import { GetDriverTeamOutputDTO } from './dtos/GetDriverTeamOutputDTO';
import { GetTeamMembershipOutputDTO } from './dtos/GetTeamMembershipOutputDTO';

// Core imports
import type { Logger } from '@core/shared/application/Logger';
import type { ITeamRepository } from '@core/racing/domain/repositories/ITeamRepository';
import type { ITeamMembershipRepository } from '@core/racing/domain/repositories/ITeamMembershipRepository';
import type { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository';

// Use cases
import { GetAllTeamsUseCase } from '@core/racing/application/use-cases/GetAllTeamsUseCase';
import { GetTeamDetailsUseCase } from '@core/racing/application/use-cases/GetTeamDetailsUseCase';
import { GetTeamMembersUseCase } from '@core/racing/application/use-cases/GetTeamMembersUseCase';
import { GetTeamJoinRequestsUseCase } from '@core/racing/application/use-cases/GetTeamJoinRequestsUseCase';
import { CreateTeamUseCase, CreateTeamInput } from '@core/racing/application/use-cases/CreateTeamUseCase';
import { UpdateTeamUseCase, UpdateTeamInput } from '@core/racing/application/use-cases/UpdateTeamUseCase';
import { GetDriverTeamUseCase } from '@core/racing/application/use-cases/GetDriverTeamUseCase';
import { GetTeamMembershipUseCase } from '@core/racing/application/use-cases/GetTeamMembershipUseCase';

// API Presenters
import { AllTeamsPresenter } from './presenters/AllTeamsPresenter';
import { TeamDetailsPresenter } from './presenters/TeamDetailsPresenter';
import { TeamMembersPresenter } from './presenters/TeamMembersPresenter';
import { TeamJoinRequestsPresenter } from './presenters/TeamJoinRequestsPresenter';
import { DriverTeamPresenter } from './presenters/DriverTeamPresenter';
import { TeamMembershipPresenter } from './presenters/TeamMembershipPresenter';
import { CreateTeamPresenter } from './presenters/CreateTeamPresenter';
import { UpdateTeamPresenter } from './presenters/UpdateTeamPresenter';

// Tokens
import { TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN, DRIVER_REPOSITORY_TOKEN, LOGGER_TOKEN, TEAM_STATS_REPOSITORY_TOKEN, RESULT_REPOSITORY_TOKEN } from './TeamTokens';
import type { ITeamStatsRepository } from '@core/racing/domain/repositories/ITeamStatsRepository';
import type { IResultRepository } from '@core/racing/domain/repositories/IResultRepository';

@Injectable()
export class TeamService {
  constructor(
    @Inject(TEAM_REPOSITORY_TOKEN) private readonly teamRepository: ITeamRepository,
    @Inject(TEAM_MEMBERSHIP_REPOSITORY_TOKEN) private readonly membershipRepository: ITeamMembershipRepository,
    @Inject(DRIVER_REPOSITORY_TOKEN) private readonly driverRepository: IDriverRepository,
    @Inject(LOGGER_TOKEN) private readonly logger: Logger,
    @Inject(TEAM_STATS_REPOSITORY_TOKEN) private readonly teamStatsRepository: ITeamStatsRepository,
    @Inject(RESULT_REPOSITORY_TOKEN) private readonly resultRepository: IResultRepository,
    private readonly allTeamsPresenter: AllTeamsPresenter,
  ) {}

  async getAll(): Promise<GetAllTeamsOutputDTO> {
    this.logger.debug('[TeamService] Fetching all teams.');

    const useCase = new GetAllTeamsUseCase(
      this.teamRepository,
      this.membershipRepository,
      this.teamStatsRepository,
      this.resultRepository,
      this.logger,
      this.allTeamsPresenter
    );
    const result = await useCase.execute();
    if (result.isErr()) {
      this.logger.error('Error fetching all teams', new Error(result.error?.details?.message || 'Unknown error'));
      return { teams: [], totalCount: 0 };
    }

    return this.allTeamsPresenter.getResponseModel()!;
  }

  async getDetails(teamId: string, userId?: string): Promise<GetTeamDetailsOutputDTO | null> {
    this.logger.debug(`[TeamService] Fetching team details for teamId: ${teamId}, userId: ${userId}`);

    const presenter = new TeamDetailsPresenter();
    const useCase = new GetTeamDetailsUseCase(this.teamRepository, this.membershipRepository, presenter);
    const result = await useCase.execute({ teamId, driverId: userId || '' });
    if (result.isErr()) {
      this.logger.error(`Error fetching team details for teamId: ${teamId}: ${result.error?.details?.message || 'Unknown error'}`);
      return null;
    }

    return presenter.getResponseModel()!;
  }

  async getMembers(teamId: string): Promise<GetTeamMembersOutputDTO> {
    this.logger.debug(`[TeamService] Fetching team members for teamId: ${teamId}`);

    const presenter = new TeamMembersPresenter();
    const useCase = new GetTeamMembersUseCase(this.membershipRepository, this.driverRepository, this.teamRepository, this.logger, presenter);
    const result = await useCase.execute({ teamId });
    if (result.isErr()) {
      this.logger.error(`Error fetching team members for teamId: ${teamId}: ${result.error?.details?.message || 'Unknown error'}`);
      return {
        members: [],
        totalCount: 0,
        ownerCount: 0,
        managerCount: 0,
        memberCount: 0,
      };
    }

    return presenter.getResponseModel()!;
  }

  async getJoinRequests(teamId: string): Promise<GetTeamJoinRequestsOutputDTO> {
    this.logger.debug(`[TeamService] Fetching team join requests for teamId: ${teamId}`);

    const presenter = new TeamJoinRequestsPresenter();
    const useCase = new GetTeamJoinRequestsUseCase(this.membershipRepository, this.driverRepository, this.teamRepository, presenter);
    const result = await useCase.execute({ teamId });
    if (result.isErr()) {
      this.logger.error(`Error fetching team join requests for teamId: ${teamId}`, new Error(result.error?.details?.message || 'Unknown error'));
      return {
        requests: [],
        pendingCount: 0,
        totalCount: 0,
      };
    }

    return presenter.getResponseModel()!;
  }

  async create(input: CreateTeamInputDTO, userId?: string): Promise<CreateTeamOutputDTO> {
    this.logger.debug('[TeamService] Creating team', { input, userId });

    const presenter = new CreateTeamPresenter();

    const command: CreateTeamInput = {
      name: input.name,
      tag: input.tag,
      description: input.description ?? '',
      ownerId: userId || '',
      leagues: [],
    };

    const useCase = new CreateTeamUseCase(this.teamRepository, this.membershipRepository, this.logger, presenter);
    const result = await useCase.execute(command);
    if (result.isErr()) {
      this.logger.error(`Error creating team: ${result.error?.details?.message || 'Unknown error'}`);
      return { id: '', success: false };
    }

    return presenter.responseModel;
  }

  async update(teamId: string, input: UpdateTeamInputDTO, userId?: string): Promise<UpdateTeamOutputDTO> {
    this.logger.debug(`[TeamService] Updating team ${teamId}`, { input, userId });

    const presenter = new UpdateTeamPresenter();

    const command: UpdateTeamInput = {
      teamId,
      updates: {
        ...(input.name !== undefined && { name: input.name }),
        ...(input.tag !== undefined && { tag: input.tag }),
        ...(input.description !== undefined && { description: input.description }),
      },
      updatedBy: userId || '',
    };

    const useCase = new UpdateTeamUseCase(this.teamRepository, this.membershipRepository, presenter);
    const result = await useCase.execute(command);
    if (result.isErr()) {
      this.logger.error(`Error updating team ${teamId}: ${result.error?.details?.message || 'Unknown error'}`);
      return { success: false };
    }

    return presenter.responseModel;
  }

  async getDriverTeam(driverId: string): Promise<GetDriverTeamOutputDTO | null> {
    this.logger.debug(`[TeamService] Fetching team for driverId: ${driverId}`);

    const presenter = new DriverTeamPresenter();
    const useCase = new GetDriverTeamUseCase(this.teamRepository, this.membershipRepository, this.logger, presenter);
    const result = await useCase.execute({ driverId });
    if (result.isErr()) {
      this.logger.error(`Error fetching team for driverId: ${driverId}: ${result.error?.details?.message || 'Unknown error'}`);
      return null;
    }

    return presenter.getResponseModel();
  }

  async getMembership(teamId: string, driverId: string): Promise<GetTeamMembershipOutputDTO | null> {
    this.logger.debug(`[TeamService] Fetching team membership for teamId: ${teamId}, driverId: ${driverId}`);

    const presenter = new TeamMembershipPresenter();
    const useCase = new GetTeamMembershipUseCase(this.membershipRepository, this.logger, presenter);
    const result = await useCase.execute({ teamId, driverId });
    if (result.isErr()) {
      this.logger.error(`Error fetching team membership for teamId: ${teamId}, driverId: ${driverId}: ${result.error?.details?.message || 'Unknown error'}`);
      return null;
    }

    return presenter.getResponseModel();
  }
}