/**
 * Domain Entity: League
 *
 * Represents a league in the GridPilot platform.
 * Immutable entity with factory methods and domain validation.
 */

import type { IEntity } from '@core/shared/domain';
import { LeagueId } from './LeagueId';
import { LeagueName } from './LeagueName';
import { LeagueDescription } from './LeagueDescription';
import { LeagueOwnerId } from './LeagueOwnerId';
import { LeagueCreatedAt } from './LeagueCreatedAt';
import { LeagueSocialLinks } from './LeagueSocialLinks';

/**
* Stewarding decision mode for protests
*/
export type StewardingDecisionMode =
  | 'admin_only'           // Only admins can decide
  | 'steward_decides'      // Single steward makes decision
  | 'steward_vote'         // X stewards must vote to uphold
  | 'member_vote'          // X members must vote to uphold
  | 'steward_veto'         // Upheld unless X stewards vote against
  | 'member_veto';         // Upheld unless X members vote against

export interface StewardingSettings {
  /**
    * How protest decisions are made
    */
  decisionMode: StewardingDecisionMode;
  /**
    * Number of votes required to uphold/reject a protest
    * Used with steward_vote, member_vote, steward_veto, member_veto modes
    */
  requiredVotes?: number;
  /**
    * Whether to require a defense from the accused before deciding
    */
  requireDefense?: boolean;
  /**
    * Time limit (hours) for accused to submit defense
    */
  defenseTimeLimit?: number;
  /**
    * Time limit (hours) for voting to complete
    */
  voteTimeLimit?: number;
  /**
    * Time limit (hours) after race ends when protests can be filed
    */
  protestDeadlineHours?: number;
  /**
    * Time limit (hours) after race ends when stewarding is closed (no more decisions)
    */
  stewardingClosesHours?: number;
  /**
    * Whether to notify the accused when a protest is filed
    */
  notifyAccusedOnProtest?: boolean;
  /**
    * Whether to notify eligible voters when a vote is required
    */
  notifyOnVoteRequired?: boolean;
}

export interface LeagueSettings {
  pointsSystem: 'f1-2024' | 'indycar' | 'custom';
  sessionDuration?: number;
  qualifyingFormat?: 'single-lap' | 'open';
  customPoints?: Record<number, number>;
  /**
    * Maximum number of drivers allowed in the league.
    * Used for simple capacity display on the website.
    */
  maxDrivers?: number;
  /**
    * Stewarding settings for protest handling
    */
  stewarding?: StewardingSettings;
}

export class League implements IEntity<LeagueId> {
  readonly id: LeagueId;
  readonly name: LeagueName;
  readonly description: LeagueDescription;
  readonly ownerId: LeagueOwnerId;
  readonly settings: LeagueSettings;
  readonly createdAt: LeagueCreatedAt;
  readonly socialLinks: LeagueSocialLinks | undefined;

  private constructor(props: {
    id: LeagueId;
    name: LeagueName;
    description: LeagueDescription;
    ownerId: LeagueOwnerId;
    settings: LeagueSettings;
    createdAt: LeagueCreatedAt;
    socialLinks?: LeagueSocialLinks;
  }) {
    this.id = props.id;
    this.name = props.name;
    this.description = props.description;
    this.ownerId = props.ownerId;
    this.settings = props.settings;
    this.createdAt = props.createdAt;
    this.socialLinks = props.socialLinks;
  }

  /**
   * Factory method to create a new League entity
   */
  static create(props: {
    id: string;
    name: string;
    description: string;
    ownerId: string;
    settings?: Partial<LeagueSettings>;
    createdAt?: Date;
    socialLinks?: {
      discordUrl?: string;
      youtubeUrl?: string;
      websiteUrl?: string;
    };
  }): League {
    const id = LeagueId.create(props.id);
    const name = LeagueName.create(props.name);
    const description = LeagueDescription.create(props.description);
    const ownerId = LeagueOwnerId.create(props.ownerId);
    const createdAt = LeagueCreatedAt.create(props.createdAt ?? new Date());

    const defaultStewardingSettings: StewardingSettings = {
      decisionMode: 'admin_only',
      requireDefense: false,
      defenseTimeLimit: 48,
      voteTimeLimit: 72,
      protestDeadlineHours: 48,
      stewardingClosesHours: 168, // 7 days
      notifyAccusedOnProtest: true,
      notifyOnVoteRequired: true,
    };

    const defaultSettings: LeagueSettings = {
      pointsSystem: 'f1-2024',
      sessionDuration: 60,
      qualifyingFormat: 'open',
      maxDrivers: 32,
      stewarding: defaultStewardingSettings,
    };

    const socialLinks = props.socialLinks ? LeagueSocialLinks.create(props.socialLinks) : undefined;

    return new League({
      id,
      name,
      description,
      ownerId,
      settings: { ...defaultSettings, ...props.settings },
      createdAt,
      ...(socialLinks !== undefined ? { socialLinks } : {}),
    });
  }


  /**
   * Create a copy with updated properties
   */
  update(props: Partial<{
    name: string;
    description: string;
    ownerId: string;
    settings: LeagueSettings;
    socialLinks?: {
      discordUrl?: string;
      youtubeUrl?: string;
      websiteUrl?: string;
    };
  }>): League {
    const name = props.name ? LeagueName.create(props.name) : this.name;
    const description = props.description ? LeagueDescription.create(props.description) : this.description;
    const ownerId = props.ownerId ? LeagueOwnerId.create(props.ownerId) : this.ownerId;
    const socialLinks = props.socialLinks ? LeagueSocialLinks.create(props.socialLinks) : this.socialLinks;

    return new League({
      id: this.id,
      name,
      description,
      ownerId,
      settings: props.settings ?? this.settings,
      createdAt: this.createdAt,
      ...(socialLinks !== undefined ? { socialLinks } : {}),
    });
  }
}