namespace BudgetApp.Domain.Models; /// /// Value object representing a monetary amount. /// Immutable and ensures non-negative amounts. /// public class Money : IEquatable { public decimal Amount { get; } public string Currency { get; } public Money(decimal amount, string currency = "USD") { if (amount < 0) throw new ArgumentException("Amount cannot be negative.", nameof(amount)); if (string.IsNullOrWhiteSpace(currency)) throw new ArgumentException("Currency cannot be null or empty.", nameof(currency)); Amount = amount; Currency = currency; } public Money Add(Money other) { if (other == null) throw new ArgumentNullException(nameof(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); } public Money Subtract(Money other) { if (other == null) throw new ArgumentNullException(nameof(other)); if (Currency != other.Currency) throw new InvalidOperationException($"Cannot subtract money with different currencies: {Currency} and {other.Currency}"); var result = Amount - other.Amount; if (result < 0) throw new InvalidOperationException("Result cannot be negative."); return new Money(result, Currency); } public bool Equals(Money? other) { if (other == null) return false; return Amount == other.Amount && Currency == other.Currency; } public override bool Equals(object? obj) { return Equals(obj as Money); } public override int GetHashCode() { return HashCode.Combine(Amount, Currency); } public static bool operator ==(Money? left, Money? right) { if (ReferenceEquals(left, right)) return true; if (left is null || right is null) return false; return left.Equals(right); } public static bool operator !=(Money? left, Money? right) { return !(left == right); } public static Money operator +(Money left, Money right) { return left.Add(right); } public static Money operator -(Money left, Money right) { return left.Subtract(right); } public override string ToString() { return $"{Amount:F2} {Currency}"; } }