import { Result } from '@core/shared/domain/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { Driver } from '../../domain/entities/Driver';
import type { League } from '../../domain/entities/League';
import type { DriverRepository } from '../../domain/repositories/DriverRepository';
import type { LeagueMembershipRepository } from '../../domain/repositories/LeagueMembershipRepository';
import type { LeagueRepository } from '../../domain/repositories/LeagueRepository';
import type { StandingRepository } from '../../domain/repositories/StandingRepository';

export interface GetLeagueOwnerSummaryInput {
  leagueId: string;
}

export type GetLeagueOwnerSummaryErrorCode = 'LEAGUE_NOT_FOUND' | 'OWNER_NOT_FOUND' | 'REPOSITORY_ERROR';

export interface GetLeagueOwnerSummaryResult {
  league: League;
  owner: Driver;
  totalMembers: number;
  activeMembers: number;
  rating: number | null;
  rank: number | null;
}

export class GetLeagueOwnerSummaryUseCase {
  constructor(
    private readonly leagueRepository: LeagueRepository,
    private readonly driverRepository: DriverRepository,
    private readonly leagueMembershipRepository: LeagueMembershipRepository,
    private readonly standingRepository: StandingRepository,
  ) {}

  async execute(
    input: GetLeagueOwnerSummaryInput,
  ): Promise<Result<GetLeagueOwnerSummaryResult, ApplicationErrorCode<GetLeagueOwnerSummaryErrorCode, { message: string }>>> {
    try {
      const league = await this.leagueRepository.findById(input.leagueId);

      if (!league) {
        return Result.err({
          code: 'LEAGUE_NOT_FOUND',
          details: { message: 'League not found' },
        });
      }

      const owner = await this.driverRepository.findById(league.ownerId.toString());

      if (!owner) {
        return Result.err({
          code: 'OWNER_NOT_FOUND',
          details: { message: 'League owner not found' },
        });
      }

      const members = await this.leagueMembershipRepository.getLeagueMembers(input.leagueId);
      const totalMembers = members.length;
      const activeMembers = members.filter(m => m.status.toString() === 'active').length;

      // Calculate rating and rank for the owner
      let rating: number | null = null;
      let rank: number | null = null;

      try {
        // Get standing for the owner in this league
        const ownerStanding = await this.standingRepository.findByDriverIdAndLeagueId(owner.id.toString(), league.id.toString());
        
        if (ownerStanding) {
          // Calculate rating from standing
          const baseRating = 1000;
          const pointsBonus = ownerStanding.points.toNumber() * 2;
          const positionBonus = Math.max(0, 50 - (ownerStanding.position.toNumber() * 2));
          const winBonus = ownerStanding.wins * 100;
          
          rating = Math.round(baseRating + pointsBonus + positionBonus + winBonus);

          // Calculate rank among all drivers in this league
          const leagueStandings = await this.standingRepository.findByLeagueId(league.id.toString());
          const driverStats = new Map<string, { rating: number }>();

          for (const standing of leagueStandings) {
            const driverId = standing.driverId.toString();
            const standingBaseRating = 1000;
            const standingPointsBonus = standing.points.toNumber() * 2;
            const standingPositionBonus = Math.max(0, 50 - (standing.position.toNumber() * 2));
            const standingWinBonus = standing.wins * 100;
            
            const standingRating = Math.round(standingBaseRating + standingPointsBonus + standingPositionBonus + standingWinBonus);
            driverStats.set(driverId, { rating: standingRating });
          }

          const rankings = Array.from(driverStats.entries())
            .sort(([, a], [, b]) => b.rating - a.rating)
            .map(([driverId], index) => ({ driverId, rank: index + 1 }));

          const ownerRanking = rankings.find(r => r.driverId === owner.id.toString());
          rank = ownerRanking ? ownerRanking.rank : null;
        }
      } catch (error) {
        // If rating calculation fails, continue with null values
        console.error('Failed to calculate rating/rank:', error);
      }

      return Result.ok({
        league,
        owner,
        totalMembers,
        activeMembers,
        rating,
        rank,
      });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Failed to get league owner summary';

      return Result.err({
        code: 'REPOSITORY_ERROR',
        details: { message },
      });
    }
  }
}