namespace WalletService.Domain.AggregatesModel.WalletAggregate;

using WalletService.Domain.SeedWork;

/// <summary>
/// EN: Money value object representing an amount with currency
/// VI: Value object Money đại diện cho số tiền với loại tiền tệ
/// </summary>
public class Money : ValueObject
{
    /// <summary>
    /// EN: The amount of money
    /// VI: Số tiền
    /// </summary>
    public decimal Amount { get; private set; }

    /// <summary>
    /// EN: The currency code (e.g., VND, USD)
    /// VI: Mã tiền tệ (ví dụ: VND, USD)
    /// </summary>
    public string Currency { get; private set; }

    /// <summary>
    /// EN: Zero money in VND
    /// VI: Số không tiền VND
    /// </summary>
    public static Money Zero => new(0, "VND");

    protected Money() 
    { 
        Amount = 0;
        Currency = "VND";
    }

    public Money(decimal amount, string currency)
    {
        if (amount < 0)
            throw new ArgumentException("Amount cannot be negative", nameof(amount));
        
        if (string.IsNullOrWhiteSpace(currency))
            throw new ArgumentException("Currency is required", nameof(currency));

        Amount = amount;
        Currency = currency.ToUpperInvariant();
    }

    /// <summary>
    /// EN: Add two money values (must be same currency)
    /// VI: Cộng hai giá trị tiền (phải cùng loại tiền)
    /// </summary>
    public Money Add(Money other)
    {
        if (Currency != other.Currency)
            throw new InvalidOperationException($"Cannot add money with different currencies: {Currency} and {other.Currency}");

        return new Money(Amount + other.Amount, Currency);
    }

    /// <summary>
    /// EN: Subtract money value (must be same currency)
    /// VI: Trừ giá trị tiền (phải cùng loại tiền)
    /// </summary>
    public Money Subtract(Money other)
    {
        if (Currency != other.Currency)
            throw new InvalidOperationException($"Cannot subtract money with different currencies: {Currency} and {other.Currency}");

        if (Amount < other.Amount)
            throw new InvalidOperationException("Insufficient balance");

        return new Money(Amount - other.Amount, Currency);
    }

    /// <summary>
    /// EN: Check if this amount is greater than or equal to another
    /// VI: Kiểm tra xem số tiền này có lớn hơn hoặc bằng số khác không
    /// </summary>
    public bool IsGreaterThanOrEqual(Money other)
    {
        if (Currency != other.Currency)
            throw new InvalidOperationException($"Cannot compare money with different currencies: {Currency} and {other.Currency}");

        return Amount >= other.Amount;
    }

    protected override IEnumerable<object?> GetEqualityComponents()
    {
        yield return Amount;
        yield return Currency;
    }

    public override string ToString() => $"{Amount:N0} {Currency}";
}
