/**
 * Domain Value Object: LeagueVisibility
 * 
 * Represents the visibility and ranking status of a league.
 * This is a hardened version that enforces strict business rules.
 */

import type { IValueObject } from '@core/shared/domain';
import { RacingDomainValidationError } from '../errors/RacingDomainError';

export type LeagueVisibilityType = 'ranked' | 'unranked';

export interface LeagueVisibilityConstraints {
  readonly minDrivers: number;
  readonly maxDrivers: number;
  readonly isPubliclyVisible: boolean;
  readonly affectsRatings: boolean;
  readonly requiresApproval: boolean;
}

const VISIBILITY_CONSTRAINTS: Record<LeagueVisibilityType, LeagueVisibilityConstraints> = {
  ranked: {
    minDrivers: 10,
    maxDrivers: 100,
    isPubliclyVisible: true,
    affectsRatings: true,
    requiresApproval: false,
  },
  unranked: {
    minDrivers: 2,
    maxDrivers: 50,
    isPubliclyVisible: false,
    affectsRatings: false,
    requiresApproval: true,
  },
};

export interface LeagueVisibilityProps {
  type: LeagueVisibilityType;
}

export class LeagueVisibility implements IValueObject<LeagueVisibilityProps> {
  readonly type: LeagueVisibilityType;
  readonly constraints: LeagueVisibilityConstraints;

  private constructor(type: LeagueVisibilityType) {
    this.type = type;
    this.constraints = VISIBILITY_CONSTRAINTS[type];
  }

  static ranked(): LeagueVisibility {
    return new LeagueVisibility('ranked');
  }

  static unranked(): LeagueVisibility {
    return new LeagueVisibility('unranked');
  }

  static fromString(value: string): LeagueVisibility {
    if (value === 'ranked' || value === 'public') {
      return LeagueVisibility.ranked();
    }
    if (value === 'unranked' || value === 'private') {
      return LeagueVisibility.unranked();
    }
    throw new RacingDomainValidationError(`Invalid league visibility: ${value}`);
  }

  /**
   * Validates that the given driver count meets the minimum requirement
   */
  validateDriverCount(driverCount: number): { valid: boolean; error?: string } {
    if (driverCount < this.constraints.minDrivers) {
      return {
        valid: false,
        error: `${this.type === 'ranked' ? 'Ranked' : 'Unranked'} leagues require at least ${this.constraints.minDrivers} drivers`
      };
    }
    if (driverCount > this.constraints.maxDrivers) {
      return {
        valid: false,
        error: `${this.type === 'ranked' ? 'Ranked' : 'Unranked'} leagues cannot exceed ${this.constraints.maxDrivers} drivers`
      };
    }
    return { valid: true };
  }

  /**
   * Validates that the given max participants is appropriate for this visibility
   */
  validateMaxParticipants(maxParticipants: number): { valid: boolean; error?: string } {
    if (maxParticipants < this.constraints.minDrivers) {
      return {
        valid: false,
        error: `Max participants must be at least ${this.constraints.minDrivers} for ${this.type} leagues`
      };
    }
    if (maxParticipants > this.constraints.maxDrivers) {
      return {
        valid: false,
        error: `Max participants cannot exceed ${this.constraints.maxDrivers} for ${this.type} leagues`
      };
    }
    return { valid: true };
  }

  /**
   * Check if this is a ranked/public league
   */
  isRanked(): boolean {
    return this.type === 'ranked';
  }

  /**
   * Check if this is an unranked/private league
   */
  isUnranked(): boolean {
    return this.type === 'unranked';
  }

  /**
   * Get minimum required drivers
   */
  getMinDrivers(): number {
    return this.constraints.minDrivers;
  }

  /**
   * Get maximum allowed drivers
   */
  getMaxDrivers(): number {
    return this.constraints.maxDrivers;
  }

  /**
   * Check if the given driver count meets minimum requirements
   */
  meetsMinimumForVisibility(driverCount: number): boolean {
    return driverCount >= this.constraints.minDrivers;
  }

  /**
   * Convert to string for serialization
   */
  toString(): LeagueVisibilityType {
    return this.type;
  }

  /**
   * For backward compatibility with existing 'public'/'private' terminology
   */
  toLegacyString(): 'public' | 'private' {
    return this.type === 'ranked' ? 'public' : 'private';
  }

  get props(): LeagueVisibilityProps {
    return { type: this.type };
  }

  equals(other: IValueObject<LeagueVisibilityProps>): boolean {
    return this.props.type === other.props.type;
  }
}

// Export constants for validation
export const MIN_RANKED_LEAGUE_DRIVERS = VISIBILITY_CONSTRAINTS.ranked.minDrivers;
export const MAX_RANKED_LEAGUE_DRIVERS = VISIBILITY_CONSTRAINTS.ranked.maxDrivers;
export const MIN_UNRANKED_LEAGUE_DRIVERS = VISIBILITY_CONSTRAINTS.unranked.minDrivers;
export const MAX_UNRANKED_LEAGUE_DRIVERS = VISIBILITY_CONSTRAINTS.unranked.maxDrivers;