/**
 * Enhanced Result entity with detailed incident tracking
 */

import type { IEntity } from '@core/shared/domain';
import { RacingDomainValidationError } from '../errors/RacingDomainError';
import { RaceIncidents, type IncidentRecord } from '../value-objects/RaceIncidents';
import { DriverId } from './DriverId';
import { RaceId } from './RaceId';
import { LapTime } from './result/LapTime';
import { Position } from './result/Position';

export class ResultWithIncidents implements IEntity<string> {
  readonly id: string;
  readonly raceId: RaceId;
  readonly driverId: DriverId;
  readonly position: Position;
  readonly fastestLap: LapTime;
  readonly incidents: RaceIncidents;
  readonly startPosition: Position;

  private constructor(props: {
    id: string;
    raceId: RaceId;
    driverId: DriverId;
    position: Position;
    fastestLap: LapTime;
    incidents: RaceIncidents;
    startPosition: Position;
  }) {
    this.id = props.id;
    this.raceId = props.raceId;
    this.driverId = props.driverId;
    this.position = props.position;
    this.fastestLap = props.fastestLap;
    this.incidents = props.incidents;
    this.startPosition = props.startPosition;
  }

  /**
   * Factory method to create a new Result entity
   */
  static create(props: {
    id: string;
    raceId: string;
    driverId: string;
    position: number;
    fastestLap: number;
    incidents: RaceIncidents;
    startPosition: number;
  }): ResultWithIncidents {
    this.validate(props);
    const raceId = RaceId.create(props.raceId);
    const driverId = DriverId.create(props.driverId);
    const position = Position.create(props.position);
    const fastestLap = LapTime.create(props.fastestLap);
    const startPosition = Position.create(props.startPosition);
    return new ResultWithIncidents({
      id: props.id,
      raceId,
      driverId,
      position,
      fastestLap,
      incidents: props.incidents,
      startPosition,
    });
  }

  /**
   * Legacy interop: create from Result data where incidents are stored as a number.
   */
  static fromLegacy(props: {
    id: string;
    raceId: string;
    driverId: string;
    position: number;
    fastestLap: number;
    incidents: number;
    startPosition: number;
  }): ResultWithIncidents {
    const raceIncidents = RaceIncidents.fromLegacyIncidentsCount(props.incidents);
    return ResultWithIncidents.create({
      ...props,
      incidents: raceIncidents,
    });
  }

  /**
   * Domain validation logic
   */
  private static validate(props: {
    id: string;
    raceId: string;
    driverId: string;
    position: number;
    fastestLap: number;
    incidents: RaceIncidents;
    startPosition: number;
  }): void {
    if (!props.id || props.id.trim().length === 0) {
      throw new RacingDomainValidationError('Result ID is required');
    }

    if (!props.raceId || props.raceId.trim().length === 0) {
      throw new RacingDomainValidationError('Race ID is required');
    }

    if (!props.driverId || props.driverId.trim().length === 0) {
      throw new RacingDomainValidationError('Driver ID is required');
    }

    if (!Number.isInteger(props.position) || props.position < 1) {
      throw new RacingDomainValidationError('Position must be a positive integer');
    }

    if (props.fastestLap < 0) {
      throw new RacingDomainValidationError('Fastest lap cannot be negative');
    }

    if (!Number.isInteger(props.startPosition) || props.startPosition < 1) {
      throw new RacingDomainValidationError('Start position must be a positive integer');
    }
  }

  /**
   * Calculate positions gained/lost
   */
  getPositionChange(): number {
    return this.startPosition.toNumber() - this.position.toNumber();
  }

  /**
   * Check if driver finished on podium
   */
  isPodium(): boolean {
    return this.position.toNumber() <= 3;
  }

  /**
   * Check if driver had a clean race (no incidents)
   */
  isClean(): boolean {
    return this.incidents.isClean();
  }

  /**
   * Get total incident count (for backward compatibility)
   */
  getTotalIncidents(): number {
    return this.incidents.getTotalCount();
  }

  /**
   * Get incident severity score
   */
  getIncidentSeverityScore(): number {
    return this.incidents.getSeverityScore();
  }

  /**
   * Get human-readable incident summary
   */
  getIncidentSummary(): string {
    return this.incidents.getSummary();
  }

  /**
   * Add an incident to this result
   */
  addIncident(incident: IncidentRecord): ResultWithIncidents {
    const updatedIncidents = this.incidents.addIncident(incident);
    return new ResultWithIncidents({
      ...this,
      incidents: updatedIncidents,
    });
  }

  /**
   * Convert to legacy format (for backward compatibility)
   */
  toLegacyFormat() {
    return {
      id: this.id,
      raceId: this.raceId,
      driverId: this.driverId,
      position: this.position,
      fastestLap: this.fastestLap,
      incidents: this.getTotalIncidents(),
      startPosition: this.startPosition,
    };
  }
}