// EN: Reservation aggregate root for FnB.
// VI: Aggregate root Reservation cho FnB.

using FnbEngine.Domain.Exceptions;
using FnbEngine.Domain.SeedWork;

namespace FnbEngine.Domain.AggregatesModel.ReservationAggregate;

/// <summary>
/// EN: Reservation aggregate root — represents a table reservation.
/// VI: Aggregate root Reservation — đại diện cho lượt đặt bàn.
/// </summary>
public class Reservation : Entity, IAggregateRoot
{
    private Guid _shopId;
    private Guid? _tableId;
    private string _guestName = null!;
    private string? _phone;
    private int _partySize;
    private DateTime _reservationTime;
    private string _status = null!;
    private string? _note;
    private DateTime _createdAt;

    public Guid ShopId => _shopId;
    public Guid? TableId => _tableId;
    public string GuestName => _guestName;
    public string? Phone => _phone;
    public int PartySize => _partySize;
    public DateTime ReservationTime => _reservationTime;
    public string Status => _status;
    public string? Note => _note;
    public DateTime CreatedAt => _createdAt;

    protected Reservation() { }

    public Reservation(Guid shopId, string guestName, int partySize, DateTime reservationTime,
        string? phone = null, Guid? tableId = null, string? note = null)
    {
        if (shopId == Guid.Empty)
            throw new DomainException("Shop ID cannot be empty");
        if (string.IsNullOrWhiteSpace(guestName))
            throw new DomainException("Guest name cannot be empty");
        if (partySize <= 0)
            throw new DomainException("Party size must be greater than zero");

        Id = Guid.NewGuid();
        _shopId = shopId;
        _guestName = guestName.Trim();
        _phone = phone?.Trim();
        _partySize = partySize;
        _reservationTime = reservationTime;
        _tableId = tableId;
        _note = note?.Trim();
        _status = "pending";
        _createdAt = DateTime.UtcNow;
    }

    public void Confirm() => _status = "confirmed";
    public void Seat() => _status = "seated";
    public void Cancel() => _status = "cancelled";
    public void NoShow() => _status = "no_show";

    public void AssignTable(Guid tableId) => _tableId = tableId;

    public void UpdateStatus(string status)
    {
        if (status is not ("pending" or "confirmed" or "seated" or "cancelled" or "no_show"))
            throw new DomainException($"Invalid reservation status: {status}");
        _status = status;
    }
}
