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

namespace AdsBillingService.Domain.AggregatesModel.InvoiceAggregate;

/// <summary>
/// EN: Invoice aggregate root - monthly billing invoice.
/// VI: Invoice aggregate root - hóa đơn thanh toán hàng tháng.
/// </summary>
public class Invoice : Entity, IAggregateRoot
{
    private List<InvoiceLineItem> _lineItems = new();
    private Guid _billingAccountId;
    private string _invoiceNumber = null!;
    private InvoiceStatus _status;
    private DateTime _issueDate;
    private DateTime _dueDate;
    private decimal _totalAmount;

    public Guid BillingAccountId => _billingAccountId;
    public string InvoiceNumber => _invoiceNumber;
    public InvoiceStatus Status => _status;
    public DateTime IssueDate => _issueDate;
    public DateTime DueDate => _dueDate;
    public decimal TotalAmount => _totalAmount;
    public IReadOnlyCollection<InvoiceLineItem> LineItems => _lineItems.AsReadOnly();

    protected Invoice() { }

    public Invoice(Guid billingAccountId, DateTime issueDate, DateTime dueDate)
    {
        Id = Guid.NewGuid();
        _billingAccountId = billingAccountId;
        _invoiceNumber = GenerateInvoiceNumber();
        _status = InvoiceStatus.Draft;
        _issueDate = issueDate;
        _dueDate = dueDate;
        _totalAmount = 0;
    }

    /// <summary>
    /// EN: Add line item for campaign charges.
    /// VI: Thêm dòng chi tiết cho chi phí campaign.
    /// </summary>
    public void AddLineItem(Guid campaignId, string description, int quantity, decimal unitPrice)
    {
        var lineItem = new InvoiceLineItem(campaignId, description, quantity, unitPrice);
        _lineItems.Add(lineItem);
        RecalculateTotal();
    }

    /// <summary>
    /// EN: Mark invoice as issued (sent to customer).
    /// VI: Đánh dấu hóa đơn đã phát hành (gửi cho khách hàng).
    /// </summary>
    public void Issue()
    {
        if (_status != InvoiceStatus.Draft)
            throw new AdsBillingDomainException("Can only issue draft invoices");

        _status = InvoiceStatus.Issued;
    }

    /// <summary>
    /// EN: Mark invoice as paid.
    /// VI: Đánh dấu hóa đơn đã thanh toán.
    /// </summary>
    public void MarkAsPaid()
    {
        if (_status != InvoiceStatus.Issued)
            throw new AdsBillingDomainException("Can only pay issued invoices");

        _status = InvoiceStatus.Paid;
    }

    private void RecalculateTotal()
    {
        _totalAmount = _lineItems.Sum(li => li.TotalAmount);
    }

    private static string GenerateInvoiceNumber()
    {
        return $"INV-{DateTime.UtcNow:yyyyMMdd}-{Guid.NewGuid().ToString("N")[..8].ToUpper()}";
    }
}

/// <summary>
/// EN: Invoice line item entity - per-campaign charges.
/// VI: Entity dòng hóa đơn - chi phí theo campaign.
/// </summary>
public class InvoiceLineItem : Entity
{
    public Guid CampaignId { get; private set; }
    public string Description { get; private set; } = null!;
    public int Quantity { get; private set; }
    public decimal UnitPrice { get; private set; }
    public decimal TotalAmount => Quantity * UnitPrice;

    protected InvoiceLineItem() { }

    public InvoiceLineItem(Guid campaignId, string description, int quantity, decimal unitPrice)
    {
        Id = Guid.NewGuid();
        CampaignId = campaignId;
        Description = description;
        Quantity = quantity;
        UnitPrice = unitPrice;
    }
}

/// <summary>
/// EN: Invoice status enumeration.
/// VI: Enum trạng thái hóa đơn.
/// </summary>
public enum InvoiceStatus
{
    Draft = 1,
    Issued = 2,
    Paid = 3,
    Overdue = 4,
    Cancelled = 5
}
