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

namespace Baya.Application.Features.Identity.Commands.Logout;

internal sealed class LogoutCommandHandler(
    ICurrentUser currentUser,
    IUnitOfWork unitOfWork,
    IAppUserManager userManager,
    IFieldEncryptor fieldEncryptor,
    IDateTimeProvider clock)
    : IRequestHandler<LogoutCommand, OperationResult<bool>>
{
    public async ValueTask<OperationResult<bool>> Handle(LogoutCommand request, CancellationToken cancellationToken)
    {
        if (currentUser.UserId is not { } userId)
            return OperationResult<bool>.UnauthorizedResult("Not authenticated.");

        var now = clock.UtcNow;

        if (request.Everywhere || string.IsNullOrEmpty(request.RefreshToken))
        {
            await unitOfWork.UserSessionRepository.RevokeAllActiveForUserAsync(userId, now, cancellationToken);
        }
        else
        {
            var session = await unitOfWork.UserSessionRepository.GetActiveForUserByTokenHashAsync(
                userId, fieldEncryptor.Hash(request.RefreshToken), cancellationToken);
            session?.Revoke(now);
        }

        // The existing RequestLogout mechanism: rotating the security stamp makes the JWE
        // OnTokenValidated stamp check reject every outstanding access token server-side.
        var user = await userManager.GetUserByIdAsync(userId);
        if (user is null)
            return OperationResult<bool>.UnauthorizedResult("Not authenticated.");

        await userManager.UpdateSecurityStampAsync(user);
        await unitOfWork.CommitAsync();

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