/**
 * Application Use Case: DriverStatsUseCase
 * 
 * Computes detailed driver statistics from race results and standings.
 * Orchestrates repositories to provide stats data to presentation layer.
 */

import type { Logger } from '@core/shared/application';
import type { IResultRepository } from '../../domain/repositories/IResultRepository';
import type { IStandingRepository } from '../../domain/repositories/IStandingRepository';
import type { IDriverStatsUseCase, DriverStats } from './IDriverStatsUseCase';

export class DriverStatsUseCase implements IDriverStatsUseCase {
  constructor(
    private readonly resultRepository: IResultRepository,
    private readonly standingRepository: IStandingRepository,
    private readonly logger: Logger
  ) {
    this.logger.info('[DriverStatsUseCase] Initialized with real data repositories');
  }

  async getDriverStats(driverId: string): Promise<DriverStats | null> {
    this.logger.debug(`[DriverStatsUseCase] Computing stats for driver: ${driverId}`);

    try {
      // Get all results for this driver
      const results = await this.resultRepository.findByDriverId(driverId);
      
      if (results.length === 0) {
        this.logger.warn(`[DriverStatsUseCase] No results found for driver: ${driverId}`);
        return null;
      }

      // Get standings for context
      const standings = await this.standingRepository.findAll();
      const driverStanding = standings.find(s => s.driverId.toString() === driverId);

      // Calculate basic stats from results
      const wins = results.filter(r => r.position.toNumber() === 1).length;
      const podiums = results.filter(r => r.position.toNumber() <= 3).length;
      const dnfs = results.filter(r => r.position.toNumber() > 20).length;
      const totalRaces = results.length;
      
      const positions = results.map(r => r.position.toNumber());
      const avgFinish = positions.reduce((sum, pos) => sum + pos, 0) / totalRaces;
      const bestFinish = Math.min(...positions);
      const worstFinish = Math.max(...positions);

      // Calculate rating based on performance
      let rating = 1000;
      if (driverStanding) {
        // Use standing-based rating
        const pointsBonus = driverStanding.points.toNumber() * 2;
        const positionBonus = Math.max(0, 50 - (driverStanding.position.toNumber() * 2));
        const winBonus = driverStanding.wins * 100;
        rating = Math.round(1000 + pointsBonus + positionBonus + winBonus);
      } else {
        // Calculate from results if no standing
        const performanceBonus = ((totalRaces - wins) * 5) + ((totalRaces - podiums) * 2);
        rating = Math.round(1000 + (wins * 100) + (podiums * 50) - performanceBonus);
      }

      // Calculate consistency (inverse of position variance)
      const avgPosition = avgFinish;
      const variance = positions.reduce((sum, pos) => sum + Math.pow(pos - avgPosition, 2), 0) / totalRaces;
      const consistency = Math.round(Math.max(0, 100 - (variance * 2)));

      // Safety rating (simplified - based on incidents)
      const totalIncidents = results.reduce((sum, r) => sum + r.incidents.toNumber(), 0);
      const safetyRating = Math.round(Math.max(0, 100 - (totalIncidents / totalRaces)));

      // Sportsmanship rating (placeholder - could be based on penalties/protests)
      const sportsmanshipRating = 4.5;

      // Experience level
      const experienceLevel = this.determineExperienceLevel(totalRaces);

      // Overall rank
      const overallRank = driverStanding ? driverStanding.position.toNumber() : null;

      const stats: DriverStats = {
        rating,
        safetyRating,
        sportsmanshipRating,
        totalRaces,
        wins,
        podiums,
        dnfs,
        avgFinish: Math.round(avgFinish * 10) / 10,
        bestFinish,
        worstFinish,
        consistency,
        experienceLevel,
        overallRank
      };

      this.logger.debug(`[DriverStatsUseCase] Computed stats for driver ${driverId}: rating=${stats.rating}, wins=${stats.wins}`);

      return stats;
    } catch (error) {
      this.logger.error(`[DriverStatsUseCase] Error computing stats for driver ${driverId}:`, error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }

  private determineExperienceLevel(totalRaces: number): string {
    if (totalRaces >= 100) return 'Veteran';
    if (totalRaces >= 50) return 'Experienced';
    if (totalRaces >= 20) return 'Intermediate';
    if (totalRaces >= 10) return 'Rookie';
    return 'Beginner';
  }
}