#nullable enable
using Baya.Application.Common;
using Baya.Application.Contracts.Common;
using Baya.Application.Contracts.Persistence;
using Baya.Application.Models.Common;
using Mediator;

namespace Baya.Application.Features.Messaging.Commands.CloseTicket;

/// <summary>Closes a ticket (participant or staff). Idempotent — an already-closed ticket is a no-op success. The
/// owner trail comes from the audit fields.</summary>
internal sealed class CloseTicketCommandHandler(
    ICurrentUser currentUser,
    IUnitOfWork unitOfWork,
    IDateTimeProvider dateTimeProvider)
    : IRequestHandler<CloseTicketCommand, OperationResult<bool>>
{
    public async ValueTask<OperationResult<bool>> Handle(CloseTicketCommand request, CancellationToken cancellationToken)
    {
        if (currentUser.UserId is not { } userId)
            return OperationResult<bool>.UnauthorizedResult("Not authenticated.");

        var ticket = await unitOfWork.TicketRepository.GetTrackedAsync(request.TicketId, cancellationToken);
        if (ticket is null)
            return OperationResult<bool>.NotFoundResult("Ticket not found.");

        if (!StaffRoles.IsStaff(currentUser.Roles) &&
            !await unitOfWork.TicketRepository.IsActiveParticipantAsync(request.TicketId, userId, cancellationToken))
            return OperationResult<bool>.ForbiddenResult("You are not a participant on this ticket.");

        if (ticket.IsOpen)
        {
            ticket.Close(userId, dateTimeProvider.UtcNow);
            await unitOfWork.CommitAsync();
        }

        return OperationResult<bool>.SuccessResult(true);
    }
}
