// EN: Handler for OpenSessionCommand.
// VI: Handler cho OpenSessionCommand.

using MediatR;
using FnbEngine.Domain.AggregatesModel.SessionAggregate;
using FnbEngine.Domain.AggregatesModel.TableAggregate;

namespace FnbEngine.API.Application.Commands;

/// <summary>
/// EN: Handler for opening a new session.
/// VI: Handler mở phiên mới.
/// </summary>
public class OpenSessionCommandHandler : IRequestHandler<OpenSessionCommand, OpenSessionResult>
{
    private readonly ISessionRepository _sessionRepository;
    private readonly ITableRepository _tableRepository;
    private readonly ILogger<OpenSessionCommandHandler> _logger;

    public OpenSessionCommandHandler(
        ISessionRepository sessionRepository,
        ITableRepository tableRepository,
        ILogger<OpenSessionCommandHandler> logger)
    {
        _sessionRepository = sessionRepository ?? throw new ArgumentNullException(nameof(sessionRepository));
        _tableRepository = tableRepository ?? throw new ArgumentNullException(nameof(tableRepository));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    public async Task<OpenSessionResult> Handle(OpenSessionCommand request, CancellationToken cancellationToken)
    {
        _logger.LogInformation(
            "Opening session for table {TableId} with {GuestCount} guests",
            request.TableId, request.GuestCount);

        // EN: Check if table exists and is available
        // VI: Kiểm tra bàn tồn tại và còn trống
        var table = await _tableRepository.GetByIdAsync(request.TableId, cancellationToken);
        if (table == null)
        {
            throw new InvalidOperationException($"Table {request.TableId} not found");
        }

        // EN: Check if there's already an active session
        // VI: Kiểm tra đã có phiên hoạt động chưa
        var activeSession = await _sessionRepository.GetActiveByTableAsync(request.TableId, cancellationToken);
        if (activeSession != null)
        {
            throw new InvalidOperationException($"Table {request.TableId} already has an active session");
        }

        // EN: Create new session
        // VI: Tạo phiên mới
        var session = new Session(request.TableId, request.ShopId, request.GuestCount);

        // EN: Mark table as occupied
        // VI: Đánh dấu bàn đang sử dụng
        table.MarkAsOccupied();

        await _sessionRepository.AddAsync(session, cancellationToken);
        _tableRepository.Update(table);
        await _sessionRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        _logger.LogInformation(
            "Opened session {SessionId} for table {TableId}",
            session.Id, request.TableId);

        return new OpenSessionResult(session.Id);
    }
}
