/**
 * Domain Entity: Driver
 *
 * Represents a driver profile 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 { IRacingId } from '../value-objects/IRacingId';
import { DriverName } from '../value-objects/driver/DriverName';
import { CountryCode } from '../value-objects/CountryCode';
import { DriverBio } from '../value-objects/driver/DriverBio';
import { JoinedAt } from '../value-objects/JoinedAt';
import { MediaReference } from '@core/domain/media/MediaReference';

export class Driver implements IEntity<string> {
  readonly id: string;
  readonly iracingId: IRacingId;
  readonly name: DriverName;
  readonly country: CountryCode;
  readonly bio: DriverBio | undefined;
  readonly joinedAt: JoinedAt;
  readonly category: string | undefined;
  readonly avatarRef: MediaReference;

  private constructor(props: {
    id: string;
    iracingId: IRacingId;
    name: DriverName;
    country: CountryCode;
    bio?: DriverBio;
    joinedAt: JoinedAt;
    category?: string;
    avatarRef: MediaReference;
  }) {
    this.id = props.id;
    this.iracingId = props.iracingId;
    this.name = props.name;
    this.country = props.country;
    this.bio = props.bio;
    this.joinedAt = props.joinedAt;
    this.category = props.category;
    this.avatarRef = props.avatarRef;
  }

  /**
   * Factory method to create a new Driver entity
   */
  static create(props: {
    id: string;
    iracingId: string;
    name: string;
    country: string;
    bio?: string;
    joinedAt?: Date;
    category?: string;
    avatarRef?: MediaReference;
  }): Driver {
    if (!props.id || props.id.trim().length === 0) {
      throw new RacingDomainValidationError('Driver ID is required');
    }

    const driverProps: {
      id: string;
      iracingId: IRacingId;
      name: DriverName;
      country: CountryCode;
      bio?: DriverBio;
      joinedAt: JoinedAt;
      category?: string;
      avatarRef: MediaReference;
    } = {
      id: props.id,
      iracingId: IRacingId.create(props.iracingId),
      name: DriverName.create(props.name),
      country: CountryCode.create(props.country),
      joinedAt: JoinedAt.create(props.joinedAt ?? new Date()),
      avatarRef: props.avatarRef ?? MediaReference.createSystemDefault('avatar'),
    };

    if (props.bio !== undefined) {
      driverProps.bio = DriverBio.create(props.bio);
    }
    if (props.category !== undefined) {
      driverProps.category = props.category;
    }

    return new Driver(driverProps);
  }

  static rehydrate(props: {
    id: string;
    iracingId: string;
    name: string;
    country: string;
    bio?: string;
    joinedAt: Date;
    category?: string;
    avatarRef?: MediaReference;
  }): Driver {
    const driverProps: {
      id: string;
      iracingId: IRacingId;
      name: DriverName;
      country: CountryCode;
      bio?: DriverBio;
      joinedAt: JoinedAt;
      category?: string;
      avatarRef: MediaReference;
    } = {
      id: props.id,
      iracingId: IRacingId.create(props.iracingId),
      name: DriverName.create(props.name),
      country: CountryCode.create(props.country),
      joinedAt: JoinedAt.create(props.joinedAt),
      avatarRef: props.avatarRef ?? MediaReference.createSystemDefault('avatar'),
    };

    if (props.bio !== undefined) {
      driverProps.bio = DriverBio.create(props.bio);
    }
    if (props.category !== undefined) {
      driverProps.category = props.category;
    }

    return new Driver(driverProps);
  }

  /**
   * Create a copy with updated properties
   */
  update(props: Partial<{
    name: string;
    country: string;
    bio: string | undefined;
    category: string | undefined;
    avatarRef: MediaReference;
  }>): Driver {
    const nextName = 'name' in props ? DriverName.create(props.name!) : this.name;
    const nextCountry = 'country' in props ? CountryCode.create(props.country!) : this.country;
    const nextBio = 'bio' in props ? (props.bio ? DriverBio.create(props.bio) : undefined) : this.bio;
    const nextCategory = 'category' in props ? props.category : this.category;
    const nextAvatarRef = 'avatarRef' in props ? props.avatarRef! : this.avatarRef;

    const driverProps: {
      id: string;
      iracingId: IRacingId;
      name: DriverName;
      country: CountryCode;
      bio?: DriverBio;
      joinedAt: JoinedAt;
      category?: string;
      avatarRef: MediaReference;
    } = {
      id: this.id,
      iracingId: this.iracingId,
      name: nextName,
      country: nextCountry,
      joinedAt: this.joinedAt,
      avatarRef: nextAvatarRef,
    };

    if (nextBio !== undefined) {
      driverProps.bio = nextBio;
    }
    if (nextCategory !== undefined) {
      driverProps.category = nextCategory;
    }

    return new Driver(driverProps);
  }
}