import { Result } from '../../domain/entities/Result';

/**
 * Enhanced race result generator with detailed incident types
 */
export class RaceResultGenerator {
  /**
   * Generate realistic race results with detailed incidents
   */
  static generateRaceResults(
    raceId: string,
    driverIds: string[],
    driverRatings: Map<string, number>
  ): Result[] {
    // Create driver performance data
    const driverPerformances = driverIds.map(driverId => ({
      driverId,
      rating: driverRatings.get(driverId) ?? 1500, // Default rating
      randomFactor: Math.random() - 0.5, // -0.5 to +0.5 randomization
    }));

    // Sort by performance (rating + randomization)
    driverPerformances.sort((a, b) => {
      const perfA = a.rating + (a.randomFactor * 200); // ±100 rating points randomization
      const perfB = b.rating + (b.randomFactor * 200);
      return perfB - perfA; // Higher performance first
    });

    // Generate qualifying results for start positions (similar but different from race results)
    const qualiPerformances = driverPerformances.map(p => ({
      ...p,
      randomFactor: Math.random() - 0.5, // New randomization for quali
    }));
    qualiPerformances.sort((a, b) => {
      const perfA = a.rating + (a.randomFactor * 150);
      const perfB = b.rating + (b.randomFactor * 150);
      return perfB - perfA;
    });

    // Generate results
    const results: Result[] = [];
    for (let i = 0; i < driverPerformances.length; i++) {
      const { driverId } = driverPerformances[i];
      const position = i + 1;
      const startPosition = qualiPerformances.findIndex(p => p.driverId === driverId) + 1;

      // Generate realistic lap times (90-120 seconds for a lap)
      const baseLapTime = 90000 + Math.random() * 30000;
      const positionBonus = (position - 1) * 500; // Winners are faster
      const fastestLap = Math.round(baseLapTime + positionBonus + Math.random() * 5000);

      // Generate detailed incidents
      const incidents = this.generateDetailedIncidents(position, driverPerformances.length);

      results.push(
        Result.create({
          id: `${raceId}-${driverId}`,
          raceId,
          driverId,
          position,
          startPosition,
          fastestLap,
          incidents,
        })
      );
    }

    return results;
  }

  /**
   * Generate detailed incidents with specific types
   */
  private static generateDetailedIncidents(position: number, totalDrivers: number): number {
    // Base probability increases for lower positions (more aggressive driving)
    const baseProbability = Math.min(0.85, position / totalDrivers + 0.1);

    // Add some randomness
    const randomFactor = Math.random();

    if (randomFactor > baseProbability) {
      return 0; // Clean race
    }

    // Determine incident severity based on position and randomness
    const severityRoll = Math.random();

    if (severityRoll < 0.4) {
      // Minor incident (track limits, small contact)
      return 1;
    } else if (severityRoll < 0.7) {
      // Moderate incident (off-track, contact with damage)
      return 2;
    } else if (severityRoll < 0.9) {
      // Major incident (spin, collision)
      return 3;
    } else {
      // Severe incident (multiple cars involved, safety car)
      return Math.floor(Math.random() * 2) + 3; // 3-4 incidents
    }
  }

  /**
   * Get incident type description for a given incident count
   */
  static getIncidentDescription(incidents: number): string {
    switch (incidents) {
      case 0:
        return 'Clean race';
      case 1:
        return 'Track limits violation';
      case 2:
        return 'Contact with another car';
      case 3:
        return 'Off-track incident';
      case 4:
        return 'Collision requiring safety car';
      default:
        return `${incidents} incidents`;
    }
  }

  /**
   * Calculate incident penalty points for standings
   */
  static getIncidentPenaltyPoints(incidents: number): number {
    // Each incident deducts points from championship standings
    return Math.max(0, incidents - 1) * 2; // First incident free, then 2 points each
  }
}