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

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

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

// Tokens
import {
    CREATE_TEAM_USE_CASE_TOKEN,
    GET_ALL_TEAMS_USE_CASE_TOKEN,
    GET_DRIVER_TEAM_USE_CASE_TOKEN,
    GET_TEAM_DETAILS_USE_CASE_TOKEN,
    GET_TEAM_JOIN_REQUESTS_USE_CASE_TOKEN,
    GET_TEAM_MEMBERS_USE_CASE_TOKEN,
    GET_TEAM_MEMBERS_USE_CASE_TOKEN as GET_TEAM_MEMBERSHIP_USE_CASE_TOKEN,
    GET_TEAMS_LEADERBOARD_USE_CASE_TOKEN,
    JOIN_TEAM_USE_CASE_TOKEN,
    LOGGER_TOKEN,
    UPDATE_TEAM_USE_CASE_TOKEN,
} from './TeamTokens';

import { TeamsLeaderboardPresenter } from './presenters/TeamsLeaderboardPresenter';

@Injectable()
export class TeamService {
  constructor(
    @Inject(GET_ALL_TEAMS_USE_CASE_TOKEN) private readonly getAllTeamsUseCase: GetAllTeamsUseCase,
    @Inject(GET_TEAM_DETAILS_USE_CASE_TOKEN) private readonly getTeamDetailsUseCase: GetTeamDetailsUseCase,
    @Inject(GET_TEAM_MEMBERS_USE_CASE_TOKEN) private readonly getTeamMembersUseCase: GetTeamMembersUseCase,
    @Inject(GET_TEAM_JOIN_REQUESTS_USE_CASE_TOKEN) private readonly getTeamJoinRequestsUseCase: GetTeamJoinRequestsUseCase,
    @Inject(CREATE_TEAM_USE_CASE_TOKEN) private readonly createTeamUseCase: CreateTeamUseCase,
    @Inject(UPDATE_TEAM_USE_CASE_TOKEN) private readonly updateTeamUseCase: UpdateTeamUseCase,
    @Inject(GET_DRIVER_TEAM_USE_CASE_TOKEN) private readonly getDriverTeamUseCase: GetDriverTeamUseCase,
    @Inject(GET_TEAM_MEMBERSHIP_USE_CASE_TOKEN) private readonly getTeamMembershipUseCase: GetTeamMembershipUseCase,
    @Inject(JOIN_TEAM_USE_CASE_TOKEN) private readonly joinTeamUseCase: JoinTeamUseCase,
    @Inject(GET_TEAMS_LEADERBOARD_USE_CASE_TOKEN) private readonly getTeamsLeaderboardUseCase: GetTeamsLeaderboardUseCase,
    @Inject(TeamsLeaderboardPresenter) private readonly teamsLeaderboardPresenter: TeamsLeaderboardPresenter,
    @Inject(LOGGER_TOKEN) private readonly logger: Logger,
  ) {}

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

    const result = await this.getAllTeamsUseCase.execute({});
    if (result.isErr()) {
      this.logger.error('Error fetching all teams', new Error(result.unwrapErr().details?.message || 'Unknown error'));
      return { teams: [], totalCount: 0 };
    }

    const value = result.unwrap();
    return {
      teams: value.teams.map(t => ({
        id: t.team.id,
        name: t.team.name.toString(),
        tag: t.team.tag.toString(),
        description: t.description,
        memberCount: t.memberCount,
        leagues: t.leagues,
        totalWins: t.totalWins,
        totalRaces: t.totalRaces,
        performanceLevel: t.performanceLevel,
        specialization: t.specialization,
        region: t.region,
        languages: t.languages,
        rating: t.rating,
        logoUrl: t.logoUrl,
        isRecruiting: t.isRecruiting,
      })),
      totalCount: value.totalCount,
    };
  }

  async getLeaderboard(): Promise<GetTeamsLeaderboardOutputDTO> {
    this.logger.debug('[TeamService] Fetching teams leaderboard.');

    const result = await this.getTeamsLeaderboardUseCase.execute({ leagueId: 'global' });
    if (result.isErr()) {
      this.logger.error('Error fetching teams leaderboard', new Error(result.unwrapErr().details?.message || 'Unknown error'));
      return { teams: [], recruitingCount: 0, groupsBySkillLevel: { beginner: [], intermediate: [], advanced: [], pro: [] }, topTeams: [] };
    }

    this.teamsLeaderboardPresenter.reset();
    this.teamsLeaderboardPresenter.present(result.unwrap());
    return this.teamsLeaderboardPresenter.getViewModel()!;
  }

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

    const result = await this.getTeamDetailsUseCase.execute({ teamId, driverId: userId || '' });
    if (result.isErr()) {
      this.logger.error(`Error fetching team details for teamId: ${teamId}: ${result.unwrapErr().details?.message || 'Unknown error'}`);
      return null;
    }

    const value = result.unwrap();
    // Convert to DTO
    return {
      team: {
        id: value.team.id,
        name: value.team.name.toString(),
        tag: value.team.tag.toString(),
        description: value.team.description.toString(),
        ownerId: value.team.ownerId.toString(),
        leagues: value.team.leagues.map(l => l.toString()),
        isRecruiting: value.team.isRecruiting,
        createdAt: value.team.createdAt?.toDate()?.toISOString?.() || new Date().toISOString(),
        category: undefined,
      },
      membership: value.membership ? {
        role: value.membership.role === 'driver' ? 'member' : (value.membership.role as 'owner' | 'manager' | 'member'),
        joinedAt: value.membership.joinedAt.toISOString(),
        isActive: value.membership.status === 'active',
      } : null,
      canManage: value.canManage,
    };
  }

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

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

    const value = result.unwrap();
    return {
      members: value.members.map(m => ({
        driverId: m.driver?.id || '',
        driverName: m.driver?.name?.toString() || '',
        role: m.membership.role === 'driver' ? 'member' : (m.membership.role as 'owner' | 'manager' | 'member'),
        joinedAt: m.membership.joinedAt.toISOString(),
        isActive: m.membership.status === 'active',
        avatarUrl: '', // Would need MediaResolver here
      })),
      totalCount: value.members.length,
      ownerCount: value.members.filter(m => m.membership.role === 'owner').length,
      managerCount: value.members.filter(m => m.membership.role === 'manager').length,
      memberCount: value.members.filter(m => m.membership.role === 'driver').length,
    };
  }

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

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

    const value = result.unwrap();
    return {
      requests: value.joinRequests.map(r => ({
        requestId: r.id,
        driverId: r.driverId,
        driverName: r.driver.name.toString(),
        teamId: r.teamId,
        status: 'pending',
        requestedAt: r.requestedAt.toISOString(),
        avatarUrl: '', // Would need MediaResolver here
      })),
      pendingCount: value.joinRequests.length,
      totalCount: value.joinRequests.length,
    };
  }

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

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

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

    const value = result.unwrap();
    return { id: value.team.id, success: true };
  }

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

    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 result = await this.updateTeamUseCase.execute(command);
    if (result.isErr()) {
      this.logger.error(`Error updating team ${teamId}: ${result.unwrapErr().details?.message || 'Unknown error'}`);
      return { success: false };
    }

    return { success: true };
  }

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

    const result = await this.getDriverTeamUseCase.execute({ driverId });
    if (result.isErr()) {
      this.logger.error(`Error fetching team for driverId: ${driverId}: ${result.unwrapErr().details?.message || 'Unknown error'}`);
      return null;
    }

    const value = result.unwrap();
    if (!value || !value.team) {
      return null;
    }

    return {
      team: {
        id: value.team.id,
        name: value.team.name.toString(),
        tag: value.team.tag.toString(),
        description: value.team.description.toString(),
        ownerId: value.team.ownerId.toString(),
        leagues: value.team.leagues.map(l => l.toString()),
        isRecruiting: value.team.isRecruiting,
        createdAt: value.team.createdAt?.toDate?.()?.toISOString?.() || new Date().toISOString(),
        category: undefined,
      },
      membership: {
        role: value.membership.role === 'driver' ? 'member' : (value.membership.role as 'owner' | 'manager' | 'member'),
        joinedAt: value.membership.joinedAt.toISOString(),
        isActive: value.membership.status === 'active',
      },
      isOwner: value.membership.role === 'owner',
      canManage: value.membership.role === 'owner' || value.membership.role === 'manager',
    };
  }

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

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

    const value = result.unwrap();
    return value.membership ? {
      role: value.membership.role,
      joinedAt: value.membership.joinedAt,
      isActive: value.membership.isActive,
    } : null;
  }

  async joinTeam(teamId: string, userId?: string): Promise<Record<string, unknown>> {
    this.logger.debug(`[TeamService] Joining team ${teamId} for user ${userId}`);

    if (!userId) {
      throw new Error('User ID is required');
    }

    const result = await this.joinTeamUseCase.execute({ teamId, driverId: userId });
    if (result.isErr()) {
      const error = result.unwrapErr();
      this.logger.error(`Error joining team ${teamId}: ${error?.details?.message || 'Unknown error'}`);
      return { success: false, error: error?.details?.message || 'Unknown error' };
    }

    return { success: true };
  }
}
