import type { IDriverRepository } from '../../domain/repositories/IDriverRepository';
import type { ITeamRepository } from '../../domain/repositories/ITeamRepository';
import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
import type { ISocialGraphRepository } from '@core/social/domain/repositories/ISocialGraphRepository';
import type { DriverExtendedProfileProvider } from '../ports/DriverExtendedProfileProvider';
import type { IDriverStatsUseCase, DriverStats } from './IDriverStatsUseCase';
import type { IRankingUseCase, DriverRanking } from './IRankingUseCase';
import type { Driver } from '../../domain/entities/Driver';
import type { Team } from '../../domain/entities/Team';
import type { TeamMembership } from '../../domain/types/TeamMembership';
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';

export type GetProfileOverviewInput = {
  driverId: string;
};
 
export interface ProfileOverviewStats {
  totalRaces: number;
  wins: number;
  podiums: number;
  dnfs: number;
  avgFinish: number | null;
  bestFinish: number | null;
  worstFinish: number | null;
  finishRate: number | null;
  winRate: number | null;
  podiumRate: number | null;
  percentile: number | null;
  rating: number | null;
  consistency: number | null;
  overallRank: number | null;
}

export interface ProfileOverviewFinishDistribution {
  totalRaces: number;
  wins: number;
  podiums: number;
  topTen: number;
  dnfs: number;
  other: number;
}

export interface ProfileOverviewTeamMembership {
  team: Team;
  membership: TeamMembership;
}

export interface ProfileOverviewSocialSummary {
  friendsCount: number;
  friends: Driver[];
}

export interface ProfileOverviewDriverInfo {
  driver: Driver;
  totalDrivers: number;
  globalRank: number | null;
  consistency: number | null;
  rating: number | null;
}

export type GetProfileOverviewResult = {
  driverInfo: ProfileOverviewDriverInfo;
  stats: ProfileOverviewStats | null;
  finishDistribution: ProfileOverviewFinishDistribution | null;
  teamMemberships: ProfileOverviewTeamMembership[];
  socialSummary: ProfileOverviewSocialSummary;
  extendedProfile: ReturnType<DriverExtendedProfileProvider['getExtendedProfile']>;
};
 
export type GetProfileOverviewErrorCode =
  | 'DRIVER_NOT_FOUND'
  | 'REPOSITORY_ERROR';
 
export class GetProfileOverviewUseCase {
  constructor(
    private readonly driverRepository: IDriverRepository,
    private readonly teamRepository: ITeamRepository,
    private readonly teamMembershipRepository: ITeamMembershipRepository,
    private readonly socialRepository: ISocialGraphRepository,
    private readonly driverExtendedProfileProvider: DriverExtendedProfileProvider,
    private readonly driverStatsUseCase: IDriverStatsUseCase,
    private readonly rankingUseCase: IRankingUseCase,
    private readonly output: UseCaseOutputPort<GetProfileOverviewResult>,
  ) {}
 
  async execute(
    input: GetProfileOverviewInput,
  ): Promise<
    Result<void, ApplicationErrorCode<GetProfileOverviewErrorCode, { message: string }>>
  > {
    try {
      const { driverId } = input;

      const driver = await this.driverRepository.findById(driverId);

      if (!driver) {
        return Result.err({
          code: 'DRIVER_NOT_FOUND',
          details: { message: 'Driver not found' },
        });
      }

      const [driverStats, teams, friends] = await Promise.all([
        this.driverStatsUseCase.getDriverStats(driverId),
        this.teamRepository.findAll(),
        this.socialRepository.getFriends(driverId),
      ]);

      const driverInfo = await this.buildDriverInfo(driver, driverStats);
      const stats = this.buildStats(driverStats);
      const finishDistribution = this.buildFinishDistribution(driverStats);
      const teamMemberships = await this.buildTeamMemberships(driver.id, teams);
      const socialSummary = this.buildSocialSummary(friends);
      const extendedProfile =
        this.driverExtendedProfileProvider.getExtendedProfile(driverId);

      const result: GetProfileOverviewResult = {
        driverInfo,
        stats,
        finishDistribution,
        teamMemberships,
        socialSummary,
        extendedProfile,
      };

      this.output.present(result);

      return Result.ok(undefined);
    } catch (error) {
      return Result.err({
        code: 'REPOSITORY_ERROR',
        details: {
          message:
            error instanceof Error
              ? error.message
              : 'Failed to load profile overview',
        },
      });
    }
  }

  private async buildDriverInfo(
    driver: Driver,
    stats: DriverStats | null,
  ): Promise<ProfileOverviewDriverInfo> {
    const rankings = await this.rankingUseCase.getAllDriverRankings();
    const fallbackRank = this.computeFallbackRank(driver.id, rankings);
    const totalDrivers = rankings.length;

    return {
      driver,
      totalDrivers,
      globalRank: stats?.overallRank ?? fallbackRank,
      consistency: stats?.consistency ?? null,
      rating: stats?.rating ?? null,
    };
  }

  private computeFallbackRank(
    driverId: string,
    rankings: DriverRanking[],
  ): number | null {
    const index = rankings.findIndex(entry => entry.driverId === driverId);
    if (index === -1) {
      return null;
    }
    return index + 1;
  }

  private buildStats(
    stats: DriverStats | null,
  ): ProfileOverviewStats | null {
    if (!stats) {
      return null;
    }

    const totalRaces = stats.totalRaces;
    const dnfs = stats.dnfs;
    const finishedRaces = Math.max(totalRaces - dnfs, 0);

    const finishRate = totalRaces > 0 ? (finishedRaces / totalRaces) * 100 : null;
    const winRate = totalRaces > 0 ? (stats.wins / totalRaces) * 100 : null;
    const podiumRate = totalRaces > 0 ? (stats.podiums / totalRaces) * 100 : null;

    return {
      totalRaces,
      wins: stats.wins,
      podiums: stats.podiums,
      dnfs,
      avgFinish: stats.avgFinish,
      bestFinish: stats.bestFinish,
      worstFinish: stats.worstFinish,
      finishRate,
      winRate,
      podiumRate,
      percentile: null, // Not available in new DriverStats
      rating: stats.rating,
      consistency: stats.consistency,
      overallRank: stats.overallRank,
    };
  }

  private buildFinishDistribution(
    stats: DriverStats | null,
  ): ProfileOverviewFinishDistribution | null {
    if (!stats || stats.totalRaces <= 0) {
      return null;
    }

    const totalRaces = stats.totalRaces;
    const dnfs = stats.dnfs;
    const finishedRaces = Math.max(totalRaces - dnfs, 0);

    const estimatedTopTen = Math.min(
      finishedRaces,
      Math.round(totalRaces * 0.7),
    );

    const topTen = Math.max(estimatedTopTen, stats.podiums);
    const other = Math.max(totalRaces - topTen, 0);

    return {
      totalRaces,
      wins: stats.wins,
      podiums: stats.podiums,
      topTen,
      dnfs,
      other,
    };
  }

  private async buildTeamMemberships(
    driverId: string,
    teams: Team[],
  ): Promise<ProfileOverviewTeamMembership[]> {
    const memberships: ProfileOverviewTeamMembership[] = [];

    for (const team of teams) {
      const membership = await this.teamMembershipRepository.getMembership(
        team.id,
        driverId,
      );
      if (!membership) continue;

      memberships.push({
        team,
        membership,
      });
    }

    memberships.sort(
      (a, b) => a.membership.joinedAt.getTime() - b.membership.joinedAt.getTime(),
    );

    return memberships;
  }

  private buildSocialSummary(friends: Driver[]): ProfileOverviewSocialSummary {
    return {
      friendsCount: friends.length,
      friends,
    };
  }
}
