/**
 * Domain Entity: Team
 *
 * Represents a racing team in the GridPilot platform.
 * Implements the shared Entity<string> contract and encapsulates
 * basic invariants around identity and core properties.
 */

import { MediaReference } from '@core/domain/media/MediaReference';
import { Entity } from '@core/shared/domain/Entity';
import { RacingDomainValidationError } from '../errors/RacingDomainError';
import { TeamCreatedAt } from '../value-objects/TeamCreatedAt';
import { TeamDescription } from '../value-objects/TeamDescription';
import { TeamName } from '../value-objects/TeamName';
import { TeamTag } from '../value-objects/TeamTag';
import { DriverId } from './DriverId';
import { LeagueId } from './LeagueId';

export class Team extends Entity<string> {
  readonly name: TeamName;
  readonly tag: TeamTag;
  readonly description: TeamDescription;
  readonly ownerId: DriverId;
  readonly leagues: LeagueId[];
  readonly category: string | undefined;
  readonly isRecruiting: boolean;
  readonly createdAt: TeamCreatedAt;
  readonly logoRef: MediaReference;

  private constructor(props: {
    id: string;
    name: TeamName;
    tag: TeamTag;
    description: TeamDescription;
    ownerId: DriverId;
    leagues: LeagueId[];
    category: string | undefined;
    isRecruiting: boolean;
    createdAt: TeamCreatedAt;
    logoRef: MediaReference;
  }) {
    super(props.id);
    
    this.name = props.name;
    this.tag = props.tag;
    this.description = props.description;
    this.ownerId = props.ownerId;
    this.leagues = props.leagues;
    this.category = props.category;
    this.isRecruiting = props.isRecruiting;
    this.createdAt = props.createdAt;
    this.logoRef = props.logoRef;
  }

  /**
   * Factory method to create a new Team entity.
   */
  static create(props: {
    id: string;
    name: string;
    tag: string;
    description: string;
    ownerId: string;
    leagues: string[];
    category?: string;
    isRecruiting?: boolean;
    createdAt?: Date;
    logoRef?: MediaReference;
  }): Team {
    if (!props.id || props.id.trim().length === 0) {
      throw new RacingDomainValidationError('Team ID is required');
    }

    if (!Array.isArray(props.leagues)) {
      throw new RacingDomainValidationError('Team leagues must be an array');
    }

    return new Team({
      id: props.id,
      name: TeamName.create(props.name),
      tag: TeamTag.create(props.tag),
      description: TeamDescription.create(props.description),
      ownerId: DriverId.create(props.ownerId),
      leagues: props.leagues.map(leagueId => LeagueId.create(leagueId)),
      category: props.category,
      isRecruiting: props.isRecruiting ?? false,
      createdAt: TeamCreatedAt.create(props.createdAt ?? new Date()),
      logoRef: props.logoRef ?? MediaReference.createSystemDefault('logo'),
    });
  }

  static rehydrate(props: {
    id: string;
    name: string;
    tag: string;
    description: string;
    ownerId: string;
    leagues: string[];
    category?: string;
    isRecruiting: boolean;
    createdAt: Date;
    logoRef?: MediaReference;
  }): Team {
    if (!props.id || props.id.trim().length === 0) {
      throw new RacingDomainValidationError('Team ID is required');
    }

    if (!Array.isArray(props.leagues)) {
      throw new RacingDomainValidationError('Team leagues must be an array');
    }

    return new Team({
      id: props.id,
      name: TeamName.create(props.name),
      tag: TeamTag.create(props.tag),
      description: TeamDescription.create(props.description),
      ownerId: DriverId.create(props.ownerId),
      leagues: props.leagues.map(leagueId => LeagueId.create(leagueId)),
      category: props.category,
      isRecruiting: props.isRecruiting,
      createdAt: TeamCreatedAt.create(props.createdAt),
      logoRef: props.logoRef ?? MediaReference.createSystemDefault('logo'),
    });
  }

  /**
   * Create a copy with updated properties.
   */
  update(props: Partial<{
    name: string;
    tag: string;
    description: string;
    ownerId: string;
    leagues: string[];
    category: string | undefined;
    isRecruiting: boolean;
    logoRef: MediaReference;
  }>): Team {
    const nextName = 'name' in props ? TeamName.create(props.name!) : this.name;
    const nextTag = 'tag' in props ? TeamTag.create(props.tag!) : this.tag;
    const nextDescription = 'description' in props ? TeamDescription.create(props.description!) : this.description;
    const nextOwnerId = 'ownerId' in props ? DriverId.create(props.ownerId!) : this.ownerId;
    const nextLeagues = 'leagues' in props ? props.leagues!.map(leagueId => LeagueId.create(leagueId)) : this.leagues;
    const nextCategory = 'category' in props ? props.category : this.category;
    const nextIsRecruiting = 'isRecruiting' in props ? props.isRecruiting! : this.isRecruiting;
    const nextLogoRef = 'logoRef' in props ? props.logoRef! : this.logoRef;

    return new Team({
      id: this.id,
      name: nextName,
      tag: nextTag,
      description: nextDescription,
      ownerId: nextOwnerId,
      leagues: nextLeagues,
      category: nextCategory,
      isRecruiting: nextIsRecruiting,
      createdAt: this.createdAt,
      logoRef: nextLogoRef,
    });
  }

  equals(other: Entity<string>): boolean {
    if (!(other instanceof Team)) {
      return false;
    }
    return this.id === other.id;
  }
}