import { Entity } from '@core/shared/domain/Entity';
import {
    RacingDomainInvariantError,
    RacingDomainValidationError,
} from '../../errors/RacingDomainError';
import { MaxParticipants } from '../../value-objects/MaxParticipants';
import { ParticipantCount } from '../../value-objects/ParticipantCount';
import type { SeasonDropPolicy } from '../../value-objects/SeasonDropPolicy';
import type { SeasonSchedule } from '../../value-objects/SeasonSchedule';
import type { SeasonScoringConfig } from '../../value-objects/SeasonScoringConfig';
import { SeasonStatus, SeasonStatusValue } from '../../value-objects/SeasonStatus';
import type { SeasonStewardingConfig } from '../../value-objects/SeasonStewardingConfig';

export class Season extends Entity<string> {
  readonly leagueId: string;
  readonly gameId: string;
  readonly name: string;
  readonly year: number | undefined;
  readonly order: number | undefined;
  readonly status: SeasonStatus;
  readonly startDate: Date | undefined;
  readonly endDate: Date | undefined;
  readonly schedule: SeasonSchedule | undefined;
  readonly schedulePublished: boolean;
  readonly scoringConfig: SeasonScoringConfig | undefined;
  readonly dropPolicy: SeasonDropPolicy | undefined;
  readonly stewardingConfig: SeasonStewardingConfig | undefined;
  readonly maxDrivers: number | undefined;

  // Domain state for business rule enforcement
  private readonly _participantCount: ParticipantCount;

  private constructor(props: {
    id: string;
    leagueId: string;
    gameId: string;
    name: string;
    year?: number;
    order?: number;
    status: SeasonStatus;
    startDate?: Date;
    endDate?: Date;
    schedule?: SeasonSchedule;
    schedulePublished: boolean;
    scoringConfig?: SeasonScoringConfig;
    dropPolicy?: SeasonDropPolicy;
    stewardingConfig?: SeasonStewardingConfig;
    maxDrivers?: number;
    participantCount: ParticipantCount;
  }) {
    super(props.id);
    
    this.leagueId = props.leagueId;
    this.gameId = props.gameId;
    this.name = props.name;
    this.year = props.year;
    this.order = props.order;
    this.status = props.status;
    this.startDate = props.startDate;
    this.endDate = props.endDate;
    this.schedule = props.schedule;
    this.schedulePublished = props.schedulePublished;
    this.scoringConfig = props.scoringConfig;
    this.dropPolicy = props.dropPolicy;
    this.stewardingConfig = props.stewardingConfig;
    this.maxDrivers = props.maxDrivers;
    this._participantCount = props.participantCount;
  }

  static create(props: {
    id: string;
    leagueId: string;
    gameId: string;
    name: string;
    year?: number;
    order?: number;
    status?: SeasonStatusValue;
    startDate?: Date;
    endDate?: Date | undefined;
    schedule?: SeasonSchedule;
    schedulePublished?: boolean;
    scoringConfig?: SeasonScoringConfig;
    dropPolicy?: SeasonDropPolicy;
    stewardingConfig?: SeasonStewardingConfig;
    maxDrivers?: number;
    participantCount?: number;
  }): Season {
    // Validate required fields
    if (!props.id || props.id.trim().length === 0) {
      throw new RacingDomainValidationError('Season ID is required');
    }

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

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

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

    // Validate maxDrivers if provided
    if (props.maxDrivers !== undefined) {
      if (props.maxDrivers <= 0) {
        throw new RacingDomainValidationError('Season maxDrivers must be greater than 0 when provided');
      }
      if (props.maxDrivers > 100) {
        throw new RacingDomainValidationError('Season maxDrivers cannot exceed 100');
      }
    }

    // Validate participant count
    const participantCount = ParticipantCount.create(props.participantCount ?? 0);
    if (props.maxDrivers !== undefined) {
      const maxParticipants = MaxParticipants.create(props.maxDrivers);
      if (!maxParticipants.canAccommodate(participantCount.toNumber())) {
        throw new RacingDomainValidationError(
          `Participant count (${participantCount.toNumber()}) exceeds season capacity (${maxParticipants.toNumber()})`
        );
      }
    }

    // Validate status transitions if status is provided
    const status = SeasonStatus.create(props.status ?? 'planned');

    // Validate schedule if provided
    if (props.schedule) {
      // Ensure schedule dates align with season dates
      if (props.startDate && props.schedule.startDate < props.startDate) {
        throw new RacingDomainValidationError('Schedule start date cannot be before season start date');
      }
    }

    // Validate scoring config if provided
    if (props.scoringConfig) {
      if (!props.scoringConfig.scoringPresetId || props.scoringConfig.scoringPresetId.trim().length === 0) {
        throw new RacingDomainValidationError('Scoring preset ID is required');
      }
    }

    // Validate drop policy if provided
    if (props.dropPolicy) {
      if (props.dropPolicy.strategy === 'bestNResults' || props.dropPolicy.strategy === 'dropWorstN') {
        if (!props.dropPolicy.n || props.dropPolicy.n <= 0) {
          throw new RacingDomainValidationError('Drop policy requires positive n value for this strategy');
        }
      }
    }

    // Validate stewarding config if provided
    if (props.stewardingConfig) {
      Season.validateStewardingConfig(props.stewardingConfig);
    }

    return new Season({
      id: props.id,
      leagueId: props.leagueId,
      gameId: props.gameId,
      name: props.name,
      ...(props.year !== undefined ? { year: props.year } : {}),
      ...(props.order !== undefined ? { order: props.order } : {}),
      status,
      ...(props.startDate !== undefined ? { startDate: props.startDate } : {}),
      ...(props.endDate !== undefined ? { endDate: props.endDate } : {}),
      ...(props.schedule !== undefined ? { schedule: props.schedule } : {}),
      schedulePublished: props.schedulePublished ?? false,
      ...(props.scoringConfig !== undefined ? { scoringConfig: props.scoringConfig } : {}),
      ...(props.dropPolicy !== undefined ? { dropPolicy: props.dropPolicy } : {}),
      ...(props.stewardingConfig !== undefined ? { stewardingConfig: props.stewardingConfig } : {}),
      ...(props.maxDrivers !== undefined ? { maxDrivers: props.maxDrivers } : {}),
      participantCount,
    });
  }

  static rehydrate(props: {
    id: string;
    leagueId: string;
    gameId: string;
    name: string;
    year?: number;
    order?: number;
    status: SeasonStatus;
    startDate?: Date;
    endDate?: Date;
    schedule?: SeasonSchedule;
    schedulePublished: boolean;
    scoringConfig?: SeasonScoringConfig;
    dropPolicy?: SeasonDropPolicy;
    stewardingConfig?: SeasonStewardingConfig;
    maxDrivers?: number;
    participantCount: number;
  }): Season {
    const participantCount = ParticipantCount.create(props.participantCount);

    if (props.maxDrivers !== undefined) {
      const maxParticipants = MaxParticipants.create(props.maxDrivers);
      if (!maxParticipants.canAccommodate(participantCount.toNumber())) {
        throw new RacingDomainValidationError(
          `Participant count (${participantCount.toNumber()}) exceeds season capacity (${maxParticipants.toNumber()})`,
        );
      }
    }

    return new Season({
      id: props.id,
      leagueId: props.leagueId,
      gameId: props.gameId,
      name: props.name,
      ...(props.year !== undefined ? { year: props.year } : {}),
      ...(props.order !== undefined ? { order: props.order } : {}),
      status: props.status,
      ...(props.startDate !== undefined ? { startDate: props.startDate } : {}),
      ...(props.endDate !== undefined ? { endDate: props.endDate } : {}),
      ...(props.schedule !== undefined ? { schedule: props.schedule } : {}),
      schedulePublished: props.schedulePublished,
      ...(props.scoringConfig !== undefined ? { scoringConfig: props.scoringConfig } : {}),
      ...(props.dropPolicy !== undefined ? { dropPolicy: props.dropPolicy } : {}),
      ...(props.stewardingConfig !== undefined ? { stewardingConfig: props.stewardingConfig } : {}),
      ...(props.maxDrivers !== undefined ? { maxDrivers: props.maxDrivers } : {}),
      participantCount,
    });
  }
 
  /**
   * Validate stewarding configuration
   */
  private static validateStewardingConfig(config: SeasonStewardingConfig): void {
    if (!config.decisionMode) {
      throw new RacingDomainValidationError('Stewarding decision mode is required');
    }

    const votingModes = ['steward_vote', 'member_vote', 'steward_veto', 'member_veto'];
    if (votingModes.includes(config.decisionMode)) {
      if (!config.requiredVotes || config.requiredVotes <= 0) {
        throw new RacingDomainValidationError(
          'Stewarding settings with voting modes require a positive requiredVotes value'
        );
      }
    }

    if (config.requiredVotes !== undefined && !votingModes.includes(config.decisionMode)) {
      throw new RacingDomainValidationError(
        'requiredVotes should only be provided for voting/veto modes'
      );
    }

    // Validate time limits
    if (config.defenseTimeLimit !== undefined && config.defenseTimeLimit < 0) {
      throw new RacingDomainValidationError('Defense time limit must be non-negative');
    }

    if (config.voteTimeLimit !== undefined && config.voteTimeLimit <= 0) {
      throw new RacingDomainValidationError('Vote time limit must be positive');
    }

    if (config.protestDeadlineHours !== undefined && config.protestDeadlineHours <= 0) {
      throw new RacingDomainValidationError('Protest deadline must be positive');
    }

    if (config.stewardingClosesHours !== undefined && config.stewardingClosesHours <= 0) {
      throw new RacingDomainValidationError('Stewarding close time must be positive');
    }
  }

  /**
   * Domain rule: Wallet withdrawals are only allowed when season is completed
   */
  canWithdrawFromWallet(): boolean {
    return this.status.isCompleted();
  }

  /**
   * Check if season is active
   */
  isActive(): boolean {
    return this.status.isActive();
  }

  /**
   * Check if season is completed
   */
  isCompleted(): boolean {
    return this.status.isCompleted();
  }

  /**
   * Check if season is planned (not yet active)
   */
  isPlanned(): boolean {
    return this.status.isPlanned();
  }

  /**
   * Check if season can accept more participants
   */
  canAcceptMore(): boolean {
    if (this.maxDrivers === undefined) return true;
    return this._participantCount.toNumber() < this.maxDrivers;
  }

  /**
   * Get current participant count
   */
  getParticipantCount(): number {
    return this._participantCount.toNumber();
  }

  /**
   * Activate the season from planned state.
   */
  activate(): Season {
    const transition = this.status.canTransitionTo('active');
    if (!transition.valid) {
      throw new RacingDomainInvariantError(transition.error!);
    }

    // Ensure start date is set
    const startDate = this.startDate ?? new Date();

    return Season.create({
      id: this.id,
      leagueId: this.leagueId,
      gameId: this.gameId,
      name: this.name,
      ...(this.year !== undefined ? { year: this.year } : {}),
      ...(this.order !== undefined ? { order: this.order } : {}),
      status: 'active',
      startDate,
      ...(this.endDate !== undefined ? { endDate: this.endDate } : {}),
      ...(this.schedule !== undefined ? { schedule: this.schedule } : {}),
      ...(this.scoringConfig !== undefined ? { scoringConfig: this.scoringConfig } : {}),
      ...(this.dropPolicy !== undefined ? { dropPolicy: this.dropPolicy } : {}),
      ...(this.stewardingConfig !== undefined ? { stewardingConfig: this.stewardingConfig } : {}),
      ...(this.maxDrivers !== undefined ? { maxDrivers: this.maxDrivers } : {}),
      participantCount: this._participantCount.toNumber(),
    });
  }

  /**
   * Mark the season as completed.
   */
  complete(): Season {
    const transition = this.status.canTransitionTo('completed');
    if (!transition.valid) {
      throw new RacingDomainInvariantError(transition.error!);
    }

    // Ensure end date is set
    const endDate = this.endDate ?? new Date();

    return Season.create({
      id: this.id,
      leagueId: this.leagueId,
      gameId: this.gameId,
      name: this.name,
      ...(this.year !== undefined ? { year: this.year } : {}),
      ...(this.order !== undefined ? { order: this.order } : {}),
      status: 'completed',
      ...(this.startDate !== undefined ? { startDate: this.startDate } : {}),
      endDate,
      ...(this.schedule !== undefined ? { schedule: this.schedule } : {}),
      ...(this.scoringConfig !== undefined ? { scoringConfig: this.scoringConfig } : {}),
      ...(this.dropPolicy !== undefined ? { dropPolicy: this.dropPolicy } : {}),
      ...(this.stewardingConfig !== undefined ? { stewardingConfig: this.stewardingConfig } : {}),
      ...(this.maxDrivers !== undefined ? { maxDrivers: this.maxDrivers } : {}),
      participantCount: this._participantCount.toNumber(),
    });
  }

  /**
   * Archive a completed season.
   */
  archive(): Season {
    const transition = this.status.canTransitionTo('archived');
    if (!transition.valid) {
      throw new RacingDomainInvariantError(transition.error!);
    }

    return Season.create({
      id: this.id,
      leagueId: this.leagueId,
      gameId: this.gameId,
      name: this.name,
      ...(this.year !== undefined ? { year: this.year } : {}),
      ...(this.order !== undefined ? { order: this.order } : {}),
      status: 'archived',
      ...(this.startDate !== undefined ? { startDate: this.startDate } : {}),
      ...(this.endDate !== undefined ? { endDate: this.endDate } : {}),
      ...(this.schedule !== undefined ? { schedule: this.schedule } : {}),
      ...(this.scoringConfig !== undefined ? { scoringConfig: this.scoringConfig } : {}),
      ...(this.dropPolicy !== undefined ? { dropPolicy: this.dropPolicy } : {}),
      ...(this.stewardingConfig !== undefined ? { stewardingConfig: this.stewardingConfig } : {}),
      ...(this.maxDrivers !== undefined ? { maxDrivers: this.maxDrivers } : {}),
      participantCount: this._participantCount.toNumber(),
    });
  }

  /**
   * Cancel a planned or active season.
   */
  cancel(): Season {
    // If already cancelled, return this (idempotent).
    if (this.status.isCancelled()) {
      return this;
    }

    const transition = this.status.canTransitionTo('cancelled');
    if (!transition.valid) {
      throw new RacingDomainInvariantError(transition.error!);
    }

    // Ensure end date is set
    const endDate = this.endDate ?? new Date();

    return Season.create({
      id: this.id,
      leagueId: this.leagueId,
      gameId: this.gameId,
      name: this.name,
      ...(this.year !== undefined ? { year: this.year } : {}),
      ...(this.order !== undefined ? { order: this.order } : {}),
      status: 'cancelled',
      ...(this.startDate !== undefined ? { startDate: this.startDate } : {}),
      endDate,
      ...(this.schedule !== undefined ? { schedule: this.schedule } : {}),
      ...(this.scoringConfig !== undefined ? { scoringConfig: this.scoringConfig } : {}),
      ...(this.dropPolicy !== undefined ? { dropPolicy: this.dropPolicy } : {}),
      ...(this.stewardingConfig !== undefined ? { stewardingConfig: this.stewardingConfig } : {}),
      ...(this.maxDrivers !== undefined ? { maxDrivers: this.maxDrivers } : {}),
      participantCount: this._participantCount.toNumber(),
    });
  }

  /**
   * Update schedule while keeping other properties intact.
   */
  withSchedule(schedule: SeasonSchedule): Season {
    // Validate schedule against season dates
    if (this.startDate && schedule.startDate < this.startDate) {
      throw new RacingDomainValidationError('Schedule start date cannot be before season start date');
    }

    return Season.create({
      id: this.id,
      leagueId: this.leagueId,
      gameId: this.gameId,
      name: this.name,
      ...(this.year !== undefined ? { year: this.year } : {}),
      ...(this.order !== undefined ? { order: this.order } : {}),
      status: this.status.toString(),
      ...(this.startDate !== undefined ? { startDate: this.startDate } : {}),
      ...(this.endDate !== undefined ? { endDate: this.endDate } : {}),
      schedule,
      schedulePublished: this.schedulePublished,
      ...(this.scoringConfig !== undefined ? { scoringConfig: this.scoringConfig } : {}),
      ...(this.dropPolicy !== undefined ? { dropPolicy: this.dropPolicy } : {}),
      ...(this.stewardingConfig !== undefined ? { stewardingConfig: this.stewardingConfig } : {}),
      ...(this.maxDrivers !== undefined ? { maxDrivers: this.maxDrivers } : {}),
      participantCount: this._participantCount.toNumber(),
    });
  }

  withSchedulePublished(published: boolean): Season {
    return Season.create({
      id: this.id,
      leagueId: this.leagueId,
      gameId: this.gameId,
      name: this.name,
      ...(this.year !== undefined ? { year: this.year } : {}),
      ...(this.order !== undefined ? { order: this.order } : {}),
      status: this.status.toString(),
      ...(this.startDate !== undefined ? { startDate: this.startDate } : {}),
      ...(this.endDate !== undefined ? { endDate: this.endDate } : {}),
      ...(this.schedule !== undefined ? { schedule: this.schedule } : {}),
      schedulePublished: published,
      ...(this.scoringConfig !== undefined ? { scoringConfig: this.scoringConfig } : {}),
      ...(this.dropPolicy !== undefined ? { dropPolicy: this.dropPolicy } : {}),
      ...(this.stewardingConfig !== undefined ? { stewardingConfig: this.stewardingConfig } : {}),
      ...(this.maxDrivers !== undefined ? { maxDrivers: this.maxDrivers } : {}),
      participantCount: this._participantCount.toNumber(),
    });
  }

  /**
   * Update scoring configuration for the season.
   */
  withScoringConfig(scoringConfig: SeasonScoringConfig): Season {
    if (!scoringConfig.scoringPresetId || scoringConfig.scoringPresetId.trim().length === 0) {
      throw new RacingDomainValidationError('Scoring preset ID is required');
    }

    return Season.create({
      id: this.id,
      leagueId: this.leagueId,
      gameId: this.gameId,
      name: this.name,
      ...(this.year !== undefined ? { year: this.year } : {}),
      ...(this.order !== undefined ? { order: this.order } : {}),
      status: this.status.toString(),
      ...(this.startDate !== undefined ? { startDate: this.startDate } : {}),
      ...(this.endDate !== undefined ? { endDate: this.endDate } : {}),
      ...(this.schedule !== undefined ? { schedule: this.schedule } : {}),
      scoringConfig,
      ...(this.dropPolicy !== undefined ? { dropPolicy: this.dropPolicy } : {}),
      ...(this.stewardingConfig !== undefined ? { stewardingConfig: this.stewardingConfig } : {}),
      ...(this.maxDrivers !== undefined ? { maxDrivers: this.maxDrivers } : {}),
      participantCount: this._participantCount.toNumber(),
    });
  }

  /**
   * Update drop policy for the season.
   */
  withDropPolicy(dropPolicy: SeasonDropPolicy): Season {
    // Validate drop policy
    if (dropPolicy.strategy === 'bestNResults' || dropPolicy.strategy === 'dropWorstN') {
      if (!dropPolicy.n || dropPolicy.n <= 0) {
        throw new RacingDomainValidationError('Drop policy requires positive n value for this strategy');
      }
    }

    return Season.create({
      id: this.id,
      leagueId: this.leagueId,
      gameId: this.gameId,
      name: this.name,
      ...(this.year !== undefined ? { year: this.year } : {}),
      ...(this.order !== undefined ? { order: this.order } : {}),
      status: this.status.toString(),
      ...(this.startDate !== undefined ? { startDate: this.startDate } : {}),
      ...(this.endDate !== undefined ? { endDate: this.endDate } : {}),
      ...(this.schedule !== undefined ? { schedule: this.schedule } : {}),
      ...(this.scoringConfig !== undefined ? { scoringConfig: this.scoringConfig } : {}),
      dropPolicy,
      ...(this.stewardingConfig !== undefined ? { stewardingConfig: this.stewardingConfig } : {}),
      ...(this.maxDrivers !== undefined ? { maxDrivers: this.maxDrivers } : {}),
      participantCount: this._participantCount.toNumber(),
    });
  }

  /**
   * Update stewarding configuration for the season.
   */
  withStewardingConfig(stewardingConfig: SeasonStewardingConfig): Season {
    Season.validateStewardingConfig(stewardingConfig);

    return Season.create({
      id: this.id,
      leagueId: this.leagueId,
      gameId: this.gameId,
      name: this.name,
      ...(this.year !== undefined ? { year: this.year } : {}),
      ...(this.order !== undefined ? { order: this.order } : {}),
      status: this.status.toString(),
      ...(this.startDate !== undefined ? { startDate: this.startDate } : {}),
      ...(this.endDate !== undefined ? { endDate: this.endDate } : {}),
      ...(this.schedule !== undefined ? { schedule: this.schedule } : {}),
      ...(this.scoringConfig !== undefined ? { scoringConfig: this.scoringConfig } : {}),
      ...(this.dropPolicy !== undefined ? { dropPolicy: this.dropPolicy } : {}),
      stewardingConfig,
      ...(this.maxDrivers !== undefined ? { maxDrivers: this.maxDrivers } : {}),
      participantCount: this._participantCount.toNumber(),
    });
  }

  /**
   * Update max driver capacity for the season.
   */
  withMaxDrivers(maxDrivers: number | undefined): Season {
    if (maxDrivers !== undefined) {
      if (maxDrivers <= 0) {
        throw new RacingDomainValidationError('Season maxDrivers must be greater than 0 when provided');
      }
      if (maxDrivers > 100) {
        throw new RacingDomainValidationError('Season maxDrivers cannot exceed 100');
      }
      if (maxDrivers < this._participantCount.toNumber()) {
        throw new RacingDomainValidationError(
          `Cannot reduce max drivers (${maxDrivers}) below current participant count (${this._participantCount.toNumber()})`
        );
      }
    }

    return Season.create({
      id: this.id,
      leagueId: this.leagueId,
      gameId: this.gameId,
      name: this.name,
      ...(this.year !== undefined ? { year: this.year } : {}),
      ...(this.order !== undefined ? { order: this.order } : {}),
      status: this.status.toString(),
      ...(this.startDate !== undefined ? { startDate: this.startDate } : {}),
      ...(this.endDate !== undefined ? { endDate: this.endDate } : {}),
      ...(this.schedule !== undefined ? { schedule: this.schedule } : {}),
      ...(this.scoringConfig !== undefined ? { scoringConfig: this.scoringConfig } : {}),
      ...(this.dropPolicy !== undefined ? { dropPolicy: this.dropPolicy } : {}),
      ...(this.stewardingConfig !== undefined ? { stewardingConfig: this.stewardingConfig } : {}),
      ...(maxDrivers !== undefined ? { maxDrivers } : {}),
      participantCount: this._participantCount.toNumber(),
    });
  }

  /**
   * Add a participant to the season
   */
  addParticipant(): Season {
    if (!this.canAcceptMore()) {
      throw new RacingDomainInvariantError(
        `Season capacity (${this.maxDrivers}) would be exceeded`
      );
    }

    const newCount = this._participantCount.increment();

    return Season.create({
      id: this.id,
      leagueId: this.leagueId,
      gameId: this.gameId,
      name: this.name,
      ...(this.year !== undefined ? { year: this.year } : {}),
      ...(this.order !== undefined ? { order: this.order } : {}),
      status: this.status.toString(),
      ...(this.startDate !== undefined ? { startDate: this.startDate } : {}),
      ...(this.endDate !== undefined ? { endDate: this.endDate } : {}),
      ...(this.schedule !== undefined ? { schedule: this.schedule } : {}),
      ...(this.scoringConfig !== undefined ? { scoringConfig: this.scoringConfig } : {}),
      ...(this.dropPolicy !== undefined ? { dropPolicy: this.dropPolicy } : {}),
      ...(this.stewardingConfig !== undefined ? { stewardingConfig: this.stewardingConfig } : {}),
      ...(this.maxDrivers !== undefined ? { maxDrivers: this.maxDrivers } : {}),
      participantCount: newCount.toNumber(),
    });
  }

  /**
   * Remove a participant from the season
   */
  removeParticipant(): Season {
    if (this._participantCount.isZero()) {
      throw new RacingDomainInvariantError('Cannot remove participant: season has no participants');
    }

    const newCount = this._participantCount.decrement();

    return Season.create({
      id: this.id,
      leagueId: this.leagueId,
      gameId: this.gameId,
      name: this.name,
      ...(this.year !== undefined ? { year: this.year } : {}),
      ...(this.order !== undefined ? { order: this.order } : {}),
      status: this.status.toString(),
      ...(this.startDate !== undefined ? { startDate: this.startDate } : {}),
      ...(this.endDate !== undefined ? { endDate: this.endDate } : {}),
      ...(this.schedule !== undefined ? { schedule: this.schedule } : {}),
      ...(this.scoringConfig !== undefined ? { scoringConfig: this.scoringConfig } : {}),
      ...(this.dropPolicy !== undefined ? { dropPolicy: this.dropPolicy } : {}),
      ...(this.stewardingConfig !== undefined ? { stewardingConfig: this.stewardingConfig } : {}),
      ...(this.maxDrivers !== undefined ? { maxDrivers: this.maxDrivers } : {}),
      participantCount: newCount.toNumber(),
    });
  }

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