/**
 * Domain Entity: Standing
 *
 * Represents a championship standing in the GridPilot platform.
 * Immutable entity with factory methods and domain validation.
 */


import type { IEntity } from '@core/shared/domain';
import { RacingDomainValidationError } from '../errors/RacingDomainError';
import { LeagueId } from './LeagueId';
import { DriverId } from './DriverId';
import { Points } from '../value-objects/Points';
import { Position } from './championship/Position';

export class Standing implements IEntity<string> {
  readonly id: string;
  readonly leagueId: LeagueId;
  readonly driverId: DriverId;
  readonly points: Points;
  readonly wins: number;
  readonly position: Position;
  readonly racesCompleted: number;

  private constructor(props: {
    id: string;
    leagueId: LeagueId;
    driverId: DriverId;
    points: Points;
    wins: number;
    position: Position;
    racesCompleted: number;
  }) {
    this.id = props.id;
    this.leagueId = props.leagueId;
    this.driverId = props.driverId;
    this.points = props.points;
    this.wins = props.wins;
    this.position = props.position;
    this.racesCompleted = props.racesCompleted;
  }

  /**
   * Factory method to create a new Standing entity
   */
  static create(props: {
    id?: string;
    leagueId: string;
    driverId: string;
    points?: number;
    wins?: number;
    position?: number;
    racesCompleted?: number;
  }): Standing {
    Standing.validate(props);

    const id = props.id && props.id.trim().length > 0
      ? props.id
      : `${props.leagueId}:${props.driverId}`;

    const leagueId = LeagueId.create(props.leagueId);
    const driverId = DriverId.create(props.driverId);
    const points = Points.create(props.points ?? 0);
    const position = Position.create(props.position ?? 1); // Default to 1 for position

    return new Standing({
      id,
      leagueId,
      driverId,
      points,
      wins: props.wins ?? 0,
      position,
      racesCompleted: props.racesCompleted ?? 0,
    });
  }

  /**
   * Domain validation logic
   */
  private static validate(props: {
    id?: string;
    leagueId: string;
    driverId: string;
  }): void {
    if (!props.leagueId || props.leagueId.trim().length === 0) {
      throw new RacingDomainValidationError('League ID is required');
    }

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

  /**
   * Add points from a race result
   */
  addRaceResult(position: number, pointsSystem: Record<number, number>): Standing {
    const racePoints = pointsSystem[position] ?? 0;
    const isWin = position === 1;

    const newPoints = Points.create(this.points.toNumber() + racePoints);
    const newPosition = this.position; // Position might be updated separately

    return new Standing({
      id: this.id,
      leagueId: this.leagueId,
      driverId: this.driverId,
      points: newPoints,
      wins: this.wins + (isWin ? 1 : 0),
      position: newPosition,
      racesCompleted: this.racesCompleted + 1,
    });
  }

  /**
   * Update championship position
   */
  updatePosition(position: number): Standing {
    const newPosition = Position.create(position);

    return new Standing({
      id: this.id,
      leagueId: this.leagueId,
      driverId: this.driverId,
      points: this.points,
      wins: this.wins,
      position: newPosition,
      racesCompleted: this.racesCompleted,
    });
  }

  /**
   * Calculate average points per race
   */
  getAveragePoints(): number {
    if (this.racesCompleted === 0) return 0;
    return this.points.toNumber() / this.racesCompleted;
  }

  /**
   * Calculate win percentage
   */
  getWinPercentage(): number {
    if (this.racesCompleted === 0) return 0;
    return (this.wins / this.racesCompleted) * 100;
  }
}