using AdsBillingService.Domain.SeedWork;
using AdsBillingService.Domain.Exceptions;

namespace AdsBillingService.Domain.AggregatesModel.BillingAccountAggregate;

/// <summary>
/// EN: Billing account aggregate root - manages advertiser billing and payments.
/// VI: Billing account aggregate root - quản lý thanh toán và billing của advertiser.
/// </summary>
public class BillingAccount : Entity, IAggregateRoot
{
    private Guid _advertiserId;
    private Guid? _walletId;
    private PaymentMethodType _paymentMethod;
    private BillingThreshold? _threshold;
    private AccountStatus _status;
    private decimal _balance;
    private decimal _creditLimit;

    public Guid AdvertiserId => _advertiserId;
    public Guid? WalletId => _walletId;
    public PaymentMethodType PaymentMethod => _paymentMethod;
    public BillingThreshold? Threshold => _threshold;
    public AccountStatus Status => _status;
    public decimal Balance => _balance;
    public decimal CreditLimit => _creditLimit;
    public DateTime CreatedAt { get; private set; }
    public DateTime? UpdatedAt { get; private set; }

    protected BillingAccount() { }

    public BillingAccount(Guid advertiserId, Guid? walletId, PaymentMethodType paymentMethod)
    {
        Id = Guid.NewGuid();
        _advertiserId = advertiserId;
        _walletId = walletId;
        _paymentMethod = paymentMethod;
        _status = AccountStatus.Active;
        _balance = 0;
        _creditLimit = 0;
        CreatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Set auto-charge threshold for prepaid accounts.
    /// VI: Thiết lập ngưỡng tự động nạp tiền cho tài khoản trả trước.
    /// </summary>
    public void SetThreshold(decimal amount, bool autoCharge)
    {
        _threshold = new BillingThreshold(amount, autoCharge);
        _UpdatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Deduct amount from balance (for prepaid).
    /// VI: Trừ tiền từ số dư (cho trả trước).
    /// </summary>
    public void DeductBalance(decimal amount)
    {
        if (_paymentMethod != PaymentMethodType.Prepaid)
            throw new AdsBillingDomainException("Can only deduct from prepaid accounts");

        if (_balance < amount)
            throw new AdsBillingDomainException("Insufficient balance");

        _balance -= amount;
        _UpdatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Add balance (from wallet top-up).
    /// VI: Thêm số dư (từ nạp ví).
    /// </summary>
    public void AddBalance(decimal amount)
    {
        if (amount <= 0)
            throw new AdsBillingDomainException("Amount must be positive");

        _balance += amount;
        _UpdatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Suspend account (e.g., due to payment issues).
    /// VI: Tạm ngưng tài khoản (ví dụ do vấn đề thanh toán).
    /// </summary>
    public void Suspend()
    {
        _status = AccountStatus.Suspended;
        _UpdatedAt = DateTime.UtcNow;
    }

    private DateTime? _UpdatedAt
    {
        get => UpdatedAt;
        set => UpdatedAt = value;
    }
}

/// <summary>
/// EN: Payment method type enumeration.
/// VI: Enum loại phương thức thanh toán.
/// </summary>
public enum PaymentMethodType
{
    Prepaid = 1,   // Pay upfront via Wallet
    Postpaid = 2,  // Monthly invoice
    CreditCard = 3 // Auto-charge credit card
}

/// <summary>
/// EN: Account status enumeration.
/// VI: Enum trạng thái tài khoản.
/// </summary>
public enum AccountStatus
{
    Active = 1,
    Suspended = 2,
    Closed = 3
}

/// <summary>
/// EN: Billing threshold value object.
/// VI: Value object ngưỡng billing.
/// </summary>
public class BillingThreshold : ValueObject
{
    public decimal Amount { get; private set; }
    public bool AutoCharge { get; private set; }

    protected BillingThreshold() { }

    public BillingThreshold(decimal amount, bool autoCharge)
    {
        if (amount <= 0)
            throw new AdsBillingDomainException("Threshold amount must be positive");

        Amount = amount;
        AutoCharge = autoCharge;
    }

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