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

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

namespace FnbEngine.API.Application.Commands;

/// <summary>
/// EN: Handler for closing a session.
/// VI: Handler đóng phiên.
/// </summary>
public class CloseSessionCommandHandler : IRequestHandler<CloseSessionCommand, bool>
{
    private readonly ISessionRepository _sessionRepository;
    private readonly ITableRepository _tableRepository;
    private readonly ILogger<CloseSessionCommandHandler> _logger;

    public CloseSessionCommandHandler(
        ISessionRepository sessionRepository,
        ITableRepository tableRepository,
        ILogger<CloseSessionCommandHandler> 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<bool> Handle(CloseSessionCommand request, CancellationToken cancellationToken)
    {
        var session = await _sessionRepository.GetByIdAsync(request.SessionId, cancellationToken);
        if (session == null)
        {
            throw new InvalidOperationException($"Session {request.SessionId} not found");
        }

        // EN: Close session through domain model
        // VI: Đóng phiên thông qua domain model
        session.Close();

        // EN: Mark table as available
        // VI: Đánh dấu bàn còn trống
        var table = await _tableRepository.GetByIdAsync(session.TableId, cancellationToken);
        if (table != null)
        {
            table.MarkAsAvailable();
            _tableRepository.Update(table);
        }

        _sessionRepository.Update(session);
        await _sessionRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        _logger.LogInformation("Closed session {SessionId}", request.SessionId);

        return true;
    }
}
