namespace WalletService.Domain.AggregatesModel.PaymentAggregate;

using WalletService.Domain.Events;
using WalletService.Domain.Exceptions;
using WalletService.Domain.SeedWork;

/// <summary>
/// EN: Payment aggregate root representing a payment transaction through a gateway.
/// VI: Aggregate root thanh toan dai dien cho giao dich thanh toan qua cong thanh toan.
/// </summary>
/// <remarks>
/// EN: Tracks the lifecycle of a payment from creation through completion/failure/refund.
/// VI: Theo doi vong doi cua thanh toan tu khi tao den khi hoan thanh/that bai/hoan tien.
/// </remarks>
public class Payment : Entity, IAggregateRoot
{
    private Guid _orderId;
    private decimal _amount;
    private string _currency;
    private string _gatewayName;
    private string? _transactionId;
    private string? _paymentUrl;
    private int _statusId;
    private string? _errorCode;
    private string? _errorMessage;
    private DateTime _createdAt;
    private DateTime? _completedAt;

    /// <summary>
    /// EN: The order identifier associated with this payment.
    /// VI: Ma don hang lien ket voi thanh toan nay.
    /// </summary>
    public Guid OrderId => _orderId;

    /// <summary>
    /// EN: Payment amount.
    /// VI: So tien thanh toan.
    /// </summary>
    public decimal Amount => _amount;

    /// <summary>
    /// EN: Currency code (e.g., VND, USD).
    /// VI: Ma tien te (vd: VND, USD).
    /// </summary>
    public string Currency => _currency;

    /// <summary>
    /// EN: Name of the payment gateway used.
    /// VI: Ten cong thanh toan su dung.
    /// </summary>
    public string GatewayName => _gatewayName;

    /// <summary>
    /// EN: Transaction ID from the payment gateway.
    /// VI: Ma giao dich tu cong thanh toan.
    /// </summary>
    public string? TransactionId => _transactionId;

    /// <summary>
    /// EN: Payment URL for customer redirect.
    /// VI: URL thanh toan de chuyen huong khach hang.
    /// </summary>
    public string? PaymentUrl => _paymentUrl;

    /// <summary>
    /// EN: Payment status ID for EF Core mapping.
    /// VI: ID trang thai thanh toan cho EF Core mapping.
    /// </summary>
    public int StatusId => _statusId;

    /// <summary>
    /// EN: Payment status.
    /// VI: Trang thai thanh toan.
    /// </summary>
    public PaymentStatus Status => PaymentStatus.FromValue<PaymentStatus>(_statusId);

    /// <summary>
    /// EN: Error code if payment failed.
    /// VI: Ma loi neu thanh toan that bai.
    /// </summary>
    public string? ErrorCode => _errorCode;

    /// <summary>
    /// EN: Error message if payment failed.
    /// VI: Thong bao loi neu thanh toan that bai.
    /// </summary>
    public string? ErrorMessage => _errorMessage;

    /// <summary>
    /// EN: Payment creation timestamp.
    /// VI: Thoi diem tao thanh toan.
    /// </summary>
    public DateTime CreatedAt => _createdAt;

    /// <summary>
    /// EN: Payment completion timestamp.
    /// VI: Thoi diem hoan thanh thanh toan.
    /// </summary>
    public DateTime? CompletedAt => _completedAt;

    /// <summary>
    /// EN: EF Core parameterless constructor.
    /// VI: Constructor khong tham so cho EF Core.
    /// </summary>
    protected Payment()
    {
        _currency = string.Empty;
        _gatewayName = string.Empty;
    }

    /// <summary>
    /// EN: Create a new payment transaction.
    /// VI: Tao giao dich thanh toan moi.
    /// </summary>
    /// <param name="orderId">EN: Order identifier / VI: Ma don hang</param>
    /// <param name="amount">EN: Payment amount / VI: So tien thanh toan</param>
    /// <param name="currency">EN: Currency code / VI: Ma tien te</param>
    /// <param name="gatewayName">EN: Payment gateway name / VI: Ten cong thanh toan</param>
    public Payment(Guid orderId, decimal amount, string currency, string gatewayName)
    {
        if (orderId == Guid.Empty)
            throw new WalletDomainException("Order ID cannot be empty / Ma don hang khong duoc trong");

        if (amount <= 0)
            throw new WalletDomainException("Payment amount must be greater than zero / So tien thanh toan phai lon hon 0");

        if (string.IsNullOrWhiteSpace(currency))
            throw new WalletDomainException("Currency is required / Tien te la bat buoc");

        if (string.IsNullOrWhiteSpace(gatewayName))
            throw new WalletDomainException("Gateway name is required / Ten cong thanh toan la bat buoc");

        Id = Guid.NewGuid();
        _orderId = orderId;
        _amount = amount;
        _currency = currency.ToUpperInvariant();
        _gatewayName = gatewayName;
        _statusId = PaymentStatus.Pending.Id;
        _createdAt = DateTime.UtcNow;

        AddDomainEvent(new PaymentCreatedDomainEvent(Id, orderId, amount, currency, gatewayName));
    }

    /// <summary>
    /// EN: Mark payment as processing (gateway has accepted the request).
    /// VI: Danh dau thanh toan dang xu ly (cong thanh toan da chap nhan yeu cau).
    /// </summary>
    /// <param name="paymentUrl">EN: Payment URL for customer / VI: URL thanh toan cho khach hang</param>
    /// <param name="transactionId">EN: Gateway transaction ID / VI: Ma giao dich cong thanh toan</param>
    public void MarkAsProcessing(string? paymentUrl, string? transactionId = null)
    {
        if (_statusId != PaymentStatus.Pending.Id)
            throw new WalletDomainException(
                $"Cannot mark payment as processing from status {Status.Name} / " +
                $"Khong the danh dau thanh toan dang xu ly tu trang thai {Status.Name}");

        _statusId = PaymentStatus.Processing.Id;
        _paymentUrl = paymentUrl;
        _transactionId = transactionId;
    }

    /// <summary>
    /// EN: Complete the payment successfully.
    /// VI: Hoan thanh thanh toan thanh cong.
    /// </summary>
    /// <param name="transactionId">EN: Gateway transaction ID / VI: Ma giao dich cong thanh toan</param>
    public void Complete(string transactionId)
    {
        if (_statusId != PaymentStatus.Pending.Id && _statusId != PaymentStatus.Processing.Id)
            throw new WalletDomainException(
                $"Cannot complete payment from status {Status.Name} / " +
                $"Khong the hoan thanh thanh toan tu trang thai {Status.Name}");

        if (string.IsNullOrWhiteSpace(transactionId))
            throw new WalletDomainException("Transaction ID is required / Ma giao dich la bat buoc");

        _statusId = PaymentStatus.Completed.Id;
        _transactionId = transactionId;
        _completedAt = DateTime.UtcNow;

        AddDomainEvent(new PaymentCompletedDomainEvent(Id, _orderId, transactionId, _amount, _currency));
    }

    /// <summary>
    /// EN: Mark the payment as failed.
    /// VI: Danh dau thanh toan that bai.
    /// </summary>
    /// <param name="errorCode">EN: Error code from gateway / VI: Ma loi tu cong thanh toan</param>
    /// <param name="errorMessage">EN: Error message / VI: Thong bao loi</param>
    public void Fail(string? errorCode, string? errorMessage)
    {
        if (_statusId != PaymentStatus.Pending.Id && _statusId != PaymentStatus.Processing.Id)
            throw new WalletDomainException(
                $"Cannot fail payment from status {Status.Name} / " +
                $"Khong the danh dau that bai tu trang thai {Status.Name}");

        _statusId = PaymentStatus.Failed.Id;
        _errorCode = errorCode;
        _errorMessage = errorMessage;
        _completedAt = DateTime.UtcNow;

        AddDomainEvent(new PaymentFailedDomainEvent(Id, _orderId, errorCode, errorMessage));
    }

    /// <summary>
    /// EN: Refund the payment.
    /// VI: Hoan tien thanh toan.
    /// </summary>
    public void Refund()
    {
        if (_statusId != PaymentStatus.Completed.Id)
            throw new WalletDomainException(
                $"Can only refund completed payments / " +
                $"Chi co the hoan tien cac thanh toan da hoan thanh");

        _statusId = PaymentStatus.Refunded.Id;
    }
}
