using MediatR;
using ChatService.Domain.AggregatesModel.UserAggregate;

namespace ChatService.API.Application.Queries.Keys;

/// <summary>
/// EN: Handler for GetUserKeyBundleQuery.
/// VI: Handler cho GetUserKeyBundleQuery.
/// </summary>
public class GetUserKeyBundleQueryHandler : IRequestHandler<GetUserKeyBundleQuery, UserKeyBundleDto?>
{
    private readonly IChatUserRepository _chatUserRepository;
    private readonly ILogger<GetUserKeyBundleQueryHandler> _logger;

    public GetUserKeyBundleQueryHandler(
        IChatUserRepository chatUserRepository,
        ILogger<GetUserKeyBundleQueryHandler> logger)
    {
        _chatUserRepository = chatUserRepository;
        _logger = logger;
    }

    public async Task<UserKeyBundleDto?> Handle(GetUserKeyBundleQuery request, CancellationToken cancellationToken)
    {
        _logger.LogInformation("Getting key bundle for user {UserId}", request.TargetUserId);

        // EN: Get key bundle and consume one-time pre-key
        // VI: Lấy key bundle và consume one-time pre-key
        var (identityPublicKey, signedPreKey, signedPreKeySignature, oneTimePreKey) = 
            await _chatUserRepository.GetKeyBundleAsync(request.TargetUserId, cancellationToken);

        if (identityPublicKey == null || signedPreKey == null || signedPreKeySignature == null)
        {
            _logger.LogWarning("Key bundle not found for user {UserId}", request.TargetUserId);
            return null;
        }

        // EN: Save the consumed one-time pre-key
        // VI: Lưu one-time pre-key đã consume
        await _chatUserRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        _logger.LogInformation("Key bundle retrieved for user {UserId}, one-time key consumed: {Consumed}", 
            request.TargetUserId, oneTimePreKey != null);

        var user = await _chatUserRepository.GetByIdAsync(request.TargetUserId, cancellationToken);

        return new UserKeyBundleDto(
            request.TargetUserId,
            identityPublicKey,
            signedPreKey,
            signedPreKeySignature,
            user?.KeyBundle?.SignedPreKeyTimestamp ?? DateTime.UtcNow,
            oneTimePreKey != null 
                ? new OneTimePreKeyResultDto(oneTimePreKey.KeyId, oneTimePreKey.PublicKey) 
                : null
        );
    }
}
