/**
 * Value Object: Money
 * Represents a monetary amount with currency and platform fee calculation
 */
 
import type { ValueObject } from '@core/shared/domain/ValueObject';
import { RacingDomainValidationError } from '../errors/RacingDomainError';

export type Currency = 'USD' | 'EUR' | 'GBP';

export const isCurrency = (value: string): value is Currency =>
  value === 'USD' || value === 'EUR' || value === 'GBP';

export interface MoneyProps {
  amount: number;
  currency: Currency;
}

export class Money implements ValueObject<MoneyProps> {
  static readonly DEFAULT_PLATFORM_FEE_PERCENTAGE = 0.10;

  readonly amount: number;
  readonly currency: Currency;

  private constructor(amount: number, currency: Currency) {
    this.amount = amount;
    this.currency = currency;
  }

  static create(amount: number, currency: Currency = 'USD'): Money {
    if (amount < 0) {
      throw new RacingDomainValidationError('Money amount cannot be negative');
    }
    if (!Number.isFinite(amount)) {
      throw new RacingDomainValidationError('Money amount must be a finite number');
    }
    return new Money(amount, currency);
  }

  /**
   * Calculate a fee amount for a given percentage.
   * Defaults to the current platform fee percentage.
   */
  calculatePlatformFee(platformFeePercentage: number = Money.DEFAULT_PLATFORM_FEE_PERCENTAGE): Money {
    if (!Number.isFinite(platformFeePercentage) || platformFeePercentage < 0) {
      throw new RacingDomainValidationError('Platform fee percentage must be a non-negative finite number');
    }
    const feeAmount = this.amount * platformFeePercentage;
    return new Money(feeAmount, this.currency);
  }

  /**
   * Calculate net amount after subtracting a fee.
   * Defaults to subtracting the current platform fee percentage.
   */
  calculateNetAmount(platformFeePercentage: number = Money.DEFAULT_PLATFORM_FEE_PERCENTAGE): Money {
    const platformFee = this.calculatePlatformFee(platformFeePercentage);
    return new Money(this.amount - platformFee.amount, this.currency);
  }

  /**
   * Add two money amounts
   */
  add(other: Money): Money {
    if (this.currency !== other.currency) {
      throw new RacingDomainValidationError('Cannot add money with different currencies');
    }
    return new Money(this.amount + other.amount, this.currency);
  }

  /**
   * Subtract two money amounts
   */
  subtract(other: Money): Money {
    if (this.currency !== other.currency) {
      throw new RacingDomainValidationError('Cannot subtract money with different currencies');
    }
    const result = this.amount - other.amount;
    if (result < 0) {
      throw new RacingDomainValidationError('Subtraction would result in negative amount');
    }
    return new Money(result, this.currency);
  }

  /**
   * Check if this money is greater than another
   */
  isGreaterThan(other: Money): boolean {
    if (this.currency !== other.currency) {
      throw new RacingDomainValidationError('Cannot compare money with different currencies');
    }
    return this.amount > other.amount;
  }

  get props(): MoneyProps {
    return {
      amount: this.amount,
      currency: this.currency,
    };
  }

  /**
    * Check if this money equals another
    */
   equals(other: ValueObject<MoneyProps>): boolean {
     const a = this.props;
     const b = other.props;
     return a.amount === b.amount && a.currency === b.currency;
   }
}