/**
 * Domain Entity: Result
 *
 * Represents a race result in the GridPilot platform.
 * Immutable entity with factory methods and domain validation.
 */

import { RacingDomainValidationError } from '../../errors/RacingDomainError';
import type { IEntity } from '@core/shared/domain';
import { RaceId } from '../RaceId';
import { DriverId } from '../DriverId';
import { Position } from './Position';
import { LapTime } from './LapTime';
import { IncidentCount } from './IncidentCount';

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

  private constructor(props: {
    id: string;
    raceId: RaceId;
    driverId: DriverId;
    position: Position;
    fastestLap: LapTime;
    incidents: IncidentCount;
    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: number;
    startPosition: number;
  }): Result {
    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 incidents = IncidentCount.create(props.incidents);
    const startPosition = Position.create(props.startPosition);

    return new Result({
      id: props.id,
      raceId,
      driverId,
      position,
      fastestLap,
      incidents,
      startPosition,
    });
  }

  /**
   * Domain validation logic
   */
  private static validate(props: {
    id: string;
    raceId: string;
    driverId: string;
    position: number;
    fastestLap: number;
    incidents: number;
    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');
    }
  }

  /**
   * 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 (0 incidents)
   */
  isClean(): boolean {
    return this.incidents.toNumber() === 0;
  }
}