// EN: Order aggregate root - the orchestrator.
// VI: Aggregate root Order - bộ điều phối.

using OrderService.Domain.Events;
using OrderService.Domain.Exceptions;
using OrderService.Domain.SeedWork;

namespace OrderService.Domain.AggregatesModel.OrderAggregate;

/// <summary>
/// EN: Order aggregate root - orchestrates order processing across verticals.
/// VI: Aggregate root Order - điều phối xử lý đơn hàng qua các ngành dọc.
/// </summary>
public class Order : Entity, IAggregateRoot
{
    private Guid _shopId;
    private Guid? _customerId;
    private OrderStatus _status = null!;
    private decimal _totalAmount;
    private DateTime _createdAt;
    private DateTime? _updatedAt;

    private readonly List<OrderItem> _items = new();

    /// <summary>
    /// EN: Shop ID that owns this order.
    /// VI: ID shop sở hữu đơn hàng này.
    /// </summary>
    public Guid ShopId => _shopId;

    /// <summary>
    /// EN: Customer ID (optional for walk-in customers).
    /// VI: ID khách hàng (tùy chọn cho khách vãng lai).
    /// </summary>
    public Guid? CustomerId => _customerId;

    /// <summary>
    /// EN: Order status.
    /// VI: Trạng thái đơn hàng.
    /// </summary>
    public OrderStatus Status => _status;

    /// <summary>
    /// EN: Status ID for EF Core mapping.
    /// VI: Status ID cho EF Core mapping.
    /// </summary>
    public int StatusId { get; private set; }

    /// <summary>
    /// EN: Total amount of the order.
    /// VI: Tổng số tiền của đơn hàng.
    /// </summary>
    public decimal TotalAmount => _totalAmount;

    /// <summary>
    /// EN: Order items (line items).
    /// VI: Các items trong đơn hàng (dòng hàng).
    /// </summary>
    public IReadOnlyCollection<OrderItem> Items => _items.AsReadOnly();

    /// <summary>
    /// EN: Creation timestamp.
    /// VI: Thời gian tạo.
    /// </summary>
    public DateTime CreatedAt => _createdAt;

    /// <summary>
    /// EN: Last update timestamp.
    /// VI: Thời gian cập nhật cuối.
    /// </summary>
    public DateTime? UpdatedAt => _updatedAt;

    /// <summary>
    /// EN: Private constructor for EF Core.
    /// VI: Constructor private cho EF Core.
    /// </summary>
    protected Order()
    {
    }

    /// <summary>
    /// EN: Create a new order.
    /// VI: Tạo đơn hàng mới.
    /// </summary>
    public Order(Guid shopId, Guid? customerId = null)
    {
        if (shopId == Guid.Empty)
            throw new DomainException("Shop ID cannot be empty");

        Id = Guid.NewGuid();
        _shopId = shopId;
        _customerId = customerId;
        _status = OrderStatus.Draft;
        StatusId = OrderStatus.Draft.Id;
        _totalAmount = 0;
        _createdAt = DateTime.UtcNow;

        AddDomainEvent(new OrderCreatedDomainEvent(this));
    }

    /// <summary>
    /// EN: Add an item to the order.
    /// VI: Thêm item vào đơn hàng.
    /// </summary>
    public void AddItem(OrderItem item)
    {
        if (_status != OrderStatus.Draft)
            throw new DomainException("Cannot add items to non-draft orders");

        _items.Add(item);
        RecalculateTotal();
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Mark order as validated.
    /// VI: Đánh dấu đơn hàng đã xác thực.
    /// </summary>
    public void MarkAsValidated()
    {
        if (_status != OrderStatus.Draft)
            throw new DomainException($"Cannot validate order with status {_status.Name}");
        if (!_items.Any())
            throw new DomainException("Cannot validate order with no items");

        _status = OrderStatus.Validated;
        StatusId = OrderStatus.Validated.Id;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Mark order as paid.
    /// VI: Đánh dấu đơn hàng đã thanh toán.
    /// </summary>
    public void MarkAsPaid()
    {
        if (_status != OrderStatus.Validated)
            throw new DomainException($"Cannot mark as paid order with status {_status.Name}");

        _status = OrderStatus.Paid;
        StatusId = OrderStatus.Paid.Id;
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new OrderPaidDomainEvent(this));
    }

    /// <summary>
    /// EN: Mark order as processing.
    /// VI: Đánh dấu đơn hàng đang xử lý.
    /// </summary>
    public void MarkAsProcessing()
    {
        if (_status != OrderStatus.Paid)
            throw new DomainException($"Cannot process order with status {_status.Name}");

        _status = OrderStatus.Processing;
        StatusId = OrderStatus.Processing.Id;
        _updatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Mark order as completed.
    /// VI: Đánh dấu đơn hàng hoàn thành.
    /// </summary>
    public void MarkAsCompleted()
    {
        if (_status != OrderStatus.Processing)
            throw new DomainException($"Cannot complete order with status {_status.Name}");

        _status = OrderStatus.Completed;
        StatusId = OrderStatus.Completed.Id;
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new OrderCompletedDomainEvent(this));
    }

    /// <summary>
    /// EN: Cancel the order.
    /// VI: Hủy đơn hàng.
    /// </summary>
    public void Cancel(string reason)
    {
        if (_status == OrderStatus.Completed)
            throw new DomainException("Cannot cancel completed order");
        if (_status == OrderStatus.Cancelled)
            throw new DomainException("Order is already cancelled");

        _status = OrderStatus.Cancelled;
        StatusId = OrderStatus.Cancelled.Id;
        _updatedAt = DateTime.UtcNow;

        AddDomainEvent(new OrderCancelledDomainEvent(this, reason));
    }

    private void RecalculateTotal()
    {
        _totalAmount = _items.Sum(i => i.TotalPrice);
    }
}
