/**
 * Domain Entity: SeasonSponsorship
 *
 * Represents a sponsorship relationship between a Sponsor and a Season.
 * Aggregate root for managing sponsorship slots and pricing.
 */
 
import { Entity } from '@core/shared/domain/Entity';
import { RacingDomainInvariantError, RacingDomainValidationError } from '../../errors/RacingDomainError';

import type { Money } from '../../value-objects/Money';

export type SponsorshipTier = 'main' | 'secondary';
export type SponsorshipStatus = 'pending' | 'active' | 'ended' | 'cancelled';

export interface SeasonSponsorshipProps {
  id: string;
  seasonId: string;
  /**
   * Optional denormalized leagueId for fast league-level aggregations.
   * Must always match the owning Season's leagueId when present.
   */
  leagueId?: string;
  sponsorId: string;
  tier: SponsorshipTier;
  pricing: Money;
  status: SponsorshipStatus;
  createdAt: Date;
  activatedAt?: Date;
  endedAt?: Date;
  cancelledAt?: Date;
  description?: string;
}

export class SeasonSponsorship extends Entity<string> {
  readonly seasonId: string;
  readonly leagueId: string | undefined;
  readonly sponsorId: string;
  readonly tier: SponsorshipTier;
  readonly pricing: Money;
  readonly status: SponsorshipStatus;
  readonly createdAt: Date;
  readonly activatedAt: Date | undefined;
  readonly endedAt: Date | undefined;
  readonly cancelledAt: Date | undefined;
  readonly description: string | undefined;

  private constructor(props: SeasonSponsorshipProps) {
    super(props.id);
    
    this.seasonId = props.seasonId;
    this.leagueId = props.leagueId;
    this.sponsorId = props.sponsorId;
    this.tier = props.tier;
    this.pricing = props.pricing;
    this.status = props.status;
    this.createdAt = props.createdAt;
    this.activatedAt = props.activatedAt;
    this.endedAt = props.endedAt;
    this.cancelledAt = props.cancelledAt;
    this.description = props.description;
  }

  static create(props: Omit<SeasonSponsorshipProps, 'createdAt' | 'status'> & {
    createdAt?: Date;
    status?: SponsorshipStatus;
  }): SeasonSponsorship {
    this.validate(props);

    return new SeasonSponsorship({
      id: props.id,
      seasonId: props.seasonId,
      ...(props.leagueId !== undefined ? { leagueId: props.leagueId } : {}),
      sponsorId: props.sponsorId,
      tier: props.tier,
      pricing: props.pricing,
      status: props.status ?? 'pending',
      createdAt: props.createdAt ?? new Date(),
      ...(props.activatedAt !== undefined ? { activatedAt: props.activatedAt } : {}),
      ...(props.endedAt !== undefined ? { endedAt: props.endedAt } : {}),
      ...(props.cancelledAt !== undefined ? { cancelledAt: props.cancelledAt } : {}),
      ...(props.description !== undefined ? { description: props.description } : {}),
    });
  }

  static rehydrate(props: SeasonSponsorshipProps): SeasonSponsorship {
    return new SeasonSponsorship(props);
  }

  private static validate(props: Omit<SeasonSponsorshipProps, 'createdAt' | 'status'>): void {
    if (!props.id || props.id.trim().length === 0) {
      throw new RacingDomainValidationError('SeasonSponsorship ID is required');
    }

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

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

    if (!props.tier) {
      throw new RacingDomainValidationError('SeasonSponsorship tier is required');
    }

    if (!props.pricing) {
      throw new RacingDomainValidationError('SeasonSponsorship pricing is required');
    }

    if (props.pricing.amount <= 0) {
      throw new RacingDomainValidationError('SeasonSponsorship pricing must be greater than zero');
    }
  }

  /**
   * Activate the sponsorship
   */
  activate(): SeasonSponsorship {
    if (this.status === 'active') {
      throw new RacingDomainInvariantError('SeasonSponsorship is already active');
    }

    if (this.status === 'cancelled') {
      throw new RacingDomainInvariantError('Cannot activate a cancelled SeasonSponsorship');
    }

    if (this.status === 'ended') {
      throw new RacingDomainInvariantError('Cannot activate an ended SeasonSponsorship');
    }

    const base: SeasonSponsorshipProps = {
      id: this.id,
      seasonId: this.seasonId,
      ...(this.leagueId !== undefined ? { leagueId: this.leagueId } : {}),
      sponsorId: this.sponsorId,
      tier: this.tier,
      pricing: this.pricing,
      status: 'active',
      createdAt: this.createdAt,
      activatedAt: new Date(),
      ...(this.endedAt !== undefined ? { endedAt: this.endedAt } : {}),
      ...(this.cancelledAt !== undefined ? { cancelledAt: this.cancelledAt } : {}),
    };

    const next: SeasonSponsorshipProps =
      this.description !== undefined
        ? { ...base, description: this.description }
        : base;

    return new SeasonSponsorship(next);
  }

  /**
   * Mark the sponsorship as ended (completed term)
   */
  end(): SeasonSponsorship {
    if (this.status === 'cancelled') {
      throw new RacingDomainInvariantError('Cannot end a cancelled SeasonSponsorship');
    }

    if (this.status === 'ended') {
      throw new RacingDomainInvariantError('SeasonSponsorship is already ended');
    }

    const base: SeasonSponsorshipProps = {
      id: this.id,
      seasonId: this.seasonId,
      ...(this.leagueId !== undefined ? { leagueId: this.leagueId } : {}),
      sponsorId: this.sponsorId,
      tier: this.tier,
      pricing: this.pricing,
      status: 'ended',
      createdAt: this.createdAt,
      ...(this.activatedAt !== undefined ? { activatedAt: this.activatedAt } : {}),
      endedAt: new Date(),
      ...(this.cancelledAt !== undefined ? { cancelledAt: this.cancelledAt } : {}),
    };

    const next: SeasonSponsorshipProps =
      this.description !== undefined
        ? { ...base, description: this.description }
        : base;

    return new SeasonSponsorship(next);
  }

  /**
   * Cancel the sponsorship
   */
  cancel(): SeasonSponsorship {
    if (this.status === 'cancelled') {
      throw new RacingDomainInvariantError('SeasonSponsorship is already cancelled');
    }

    const base: SeasonSponsorshipProps = {
      id: this.id,
      seasonId: this.seasonId,
      ...(this.leagueId !== undefined ? { leagueId: this.leagueId } : {}),
      sponsorId: this.sponsorId,
      tier: this.tier,
      pricing: this.pricing,
      status: 'cancelled',
      createdAt: this.createdAt,
      ...(this.activatedAt !== undefined ? { activatedAt: this.activatedAt } : {}),
      ...(this.endedAt !== undefined ? { endedAt: this.endedAt } : {}),
      cancelledAt: new Date(),
    };

    const next: SeasonSponsorshipProps =
      this.description !== undefined
        ? { ...base, description: this.description }
        : base;

    return new SeasonSponsorship(next);
  }

  /**
   * Update pricing/terms when allowed
   */
  withPricing(pricing: Money): SeasonSponsorship {
    if (pricing.amount <= 0) {
      throw new RacingDomainValidationError('SeasonSponsorship pricing must be greater than zero');
    }

    if (this.status === 'cancelled' || this.status === 'ended') {
      throw new RacingDomainInvariantError('Cannot update pricing for ended or cancelled SeasonSponsorship');
    }

    const base: SeasonSponsorshipProps = {
      id: this.id,
      seasonId: this.seasonId,
      ...(this.leagueId !== undefined ? { leagueId: this.leagueId } : {}),
      sponsorId: this.sponsorId,
      tier: this.tier,
      pricing,
      status: this.status,
      createdAt: this.createdAt,
      ...(this.activatedAt !== undefined ? { activatedAt: this.activatedAt } : {}),
      ...(this.endedAt !== undefined ? { endedAt: this.endedAt } : {}),
      ...(this.cancelledAt !== undefined ? { cancelledAt: this.cancelledAt } : {}),
    };

    const next: SeasonSponsorshipProps =
      this.description !== undefined
        ? { ...base, description: this.description }
        : base;

    return new SeasonSponsorship(next);
  }

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

  /**
   * Get the platform fee for this sponsorship
   */
  getPlatformFee(): Money {
    return this.pricing.calculatePlatformFee();
  }

  /**
   * Get the net amount after platform fee
   */
  getNetAmount(): Money {
    return this.pricing.calculateNetAmount();
  }
}