/**
 * Domain Entity: DriverLivery
 *
 * Represents a driver's custom livery for a specific car.
 * Includes user-placed decals and league-specific overrides.
 */

import type { IEntity } from '@core/shared/domain';

import { RacingDomainValidationError, RacingDomainInvariantError } from '../errors/RacingDomainError';
import { LiveryDecal } from '../value-objects/LiveryDecal';
import { DecalOverride } from '../value-objects/DecalOverride';
import { DriverId } from '../value-objects/driver/DriverId';
import { GameId } from './GameId';
import { CarId } from '../value-objects/CarId';
import { ImageUrl } from '../value-objects/ImageUrl';

export interface DriverLiveryProps {
  id: string;
  driverId: DriverId;
  gameId: GameId;
  carId: CarId;
  uploadedImageUrl: ImageUrl;
  userDecals: LiveryDecal[];
  leagueOverrides: DecalOverride[];
  createdAt: Date;
  updatedAt: Date | undefined;
  validatedAt: Date | undefined;
}

export class DriverLivery implements IEntity<string> {
  readonly id: string;
  readonly driverId: DriverId;
  readonly gameId: GameId;
  readonly carId: CarId;
  readonly uploadedImageUrl: ImageUrl;
  readonly userDecals: LiveryDecal[];
  readonly leagueOverrides: DecalOverride[];
  readonly createdAt: Date;
  readonly updatedAt: Date | undefined;
  readonly validatedAt: Date | undefined;

  private constructor(props: DriverLiveryProps) {
    this.id = props.id;
    this.driverId = props.driverId;
    this.gameId = props.gameId;
    this.carId = props.carId;
    this.uploadedImageUrl = props.uploadedImageUrl;
    this.userDecals = props.userDecals;
    this.leagueOverrides = props.leagueOverrides;
    this.createdAt = props.createdAt ?? new Date();
    this.updatedAt = props.updatedAt;
    this.validatedAt = props.validatedAt;
  }

  static create(props: {
    id: string;
    driverId: string;
    gameId: string;
    carId: string;
    uploadedImageUrl: string;
    createdAt?: Date;
    userDecals?: LiveryDecal[];
    leagueOverrides?: DecalOverride[];
  }): DriverLivery {
    this.validate(props);

    return new DriverLivery({
      id: props.id,
      driverId: DriverId.create(props.driverId),
      gameId: GameId.create(props.gameId),
      carId: CarId.create(props.carId),
      uploadedImageUrl: ImageUrl.create(props.uploadedImageUrl),
      userDecals: props.userDecals ?? [],
      leagueOverrides: props.leagueOverrides ?? [],
      createdAt: props.createdAt ?? new Date(),
      updatedAt: undefined,
      validatedAt: undefined,
    });
  }

  private static validate(props: {
    id: string;
    driverId: string;
    gameId: string;
    carId: string;
    uploadedImageUrl: string;
  }): void {
    if (!props.id || props.id.trim().length === 0) {
      throw new RacingDomainValidationError('DriverLivery ID is required');
    }

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

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

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

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

  /**
   * Add a user decal
   */
  addDecal(decal: LiveryDecal): DriverLivery {
    if (decal.type !== 'user') {
      throw new RacingDomainInvariantError('Only user decals can be added to driver livery');
    }

    return new DriverLivery({
      id: this.id,
      driverId: this.driverId,
      gameId: this.gameId,
      carId: this.carId,
      uploadedImageUrl: this.uploadedImageUrl,
      userDecals: [...this.userDecals, decal],
      leagueOverrides: this.leagueOverrides,
      createdAt: this.createdAt,
      updatedAt: new Date(),
      validatedAt: this.validatedAt,
    });
  }

  /**
   * Remove a user decal
   */
  removeDecal(decalId: string): DriverLivery {
    const updatedDecals = this.userDecals.filter(d => d.id !== decalId);

    if (updatedDecals.length === this.userDecals.length) {
      throw new RacingDomainValidationError('Decal not found in livery');
    }

    return new DriverLivery({
      id: this.id,
      driverId: this.driverId,
      gameId: this.gameId,
      carId: this.carId,
      uploadedImageUrl: this.uploadedImageUrl,
      userDecals: updatedDecals,
      leagueOverrides: this.leagueOverrides,
      createdAt: this.createdAt,
      updatedAt: new Date(),
      validatedAt: this.validatedAt,
    });
  }

  /**
   * Update a user decal
   */
  updateDecal(decalId: string, updatedDecal: LiveryDecal): DriverLivery {
    const index = this.userDecals.findIndex(d => d.id === decalId);

    if (index === -1) {
      throw new RacingDomainValidationError('Decal not found in livery');
    }

    const updatedDecals = [...this.userDecals];
    updatedDecals[index] = updatedDecal;

    return new DriverLivery({
      id: this.id,
      driverId: this.driverId,
      gameId: this.gameId,
      carId: this.carId,
      uploadedImageUrl: this.uploadedImageUrl,
      userDecals: updatedDecals,
      leagueOverrides: this.leagueOverrides,
      createdAt: this.createdAt,
      updatedAt: new Date(),
      validatedAt: this.validatedAt,
    });
  }

  /**
   * Add or update a league-specific decal override
   */
  setLeagueOverride(leagueId: string, seasonId: string, decalId: string, newX: number, newY: number): DriverLivery {
    const existingIndex = this.leagueOverrides.findIndex(
      o => o.leagueId === leagueId && o.seasonId === seasonId && o.decalId === decalId
    );

    const override = DecalOverride.create({ leagueId, seasonId, decalId, newX, newY });

    let updatedOverrides: DecalOverride[];
    if (existingIndex >= 0) {
      updatedOverrides = [...this.leagueOverrides];
      updatedOverrides[existingIndex] = override;
    } else {
      updatedOverrides = [...this.leagueOverrides, override];
    }

    return new DriverLivery({
      id: this.id,
      driverId: this.driverId,
      gameId: this.gameId,
      carId: this.carId,
      uploadedImageUrl: this.uploadedImageUrl,
      userDecals: this.userDecals,
      leagueOverrides: updatedOverrides,
      createdAt: this.createdAt,
      updatedAt: new Date(),
      validatedAt: this.validatedAt,
    });
  }

  /**
   * Remove a league-specific override
   */
  removeLeagueOverride(leagueId: string, seasonId: string, decalId: string): DriverLivery {
    const updatedOverrides = this.leagueOverrides.filter(
      o => !(o.leagueId === leagueId && o.seasonId === seasonId && o.decalId === decalId)
    );

    return new DriverLivery({
      id: this.id,
      driverId: this.driverId,
      gameId: this.gameId,
      carId: this.carId,
      uploadedImageUrl: this.uploadedImageUrl,
      userDecals: this.userDecals,
      leagueOverrides: updatedOverrides,
      createdAt: this.createdAt,
      updatedAt: new Date(),
      validatedAt: this.validatedAt,
    });
  }

  /**
   * Get overrides for a specific league/season
   */
  getOverridesFor(leagueId: string, seasonId: string): DecalOverride[] {
    return this.leagueOverrides.filter(
      o => o.leagueId === leagueId && o.seasonId === seasonId
    );
  }

  /**
   * Mark livery as validated (no logos/text detected)
   */
  markAsValidated(): DriverLivery {
    return new DriverLivery({
      id: this.id,
      driverId: this.driverId,
      gameId: this.gameId,
      carId: this.carId,
      uploadedImageUrl: this.uploadedImageUrl,
      userDecals: this.userDecals,
      leagueOverrides: this.leagueOverrides,
      createdAt: this.createdAt,
      updatedAt: this.updatedAt,
      validatedAt: new Date(),
    });
  }

  /**
   * Check if livery is validated
   */
  isValidated(): boolean {
    return this.validatedAt !== undefined;
  }
}