using ColaFlow.Modules.Identity.Application.Services;
using ColaFlow.Modules.Identity.Domain.Repositories;
using MediatR;
using Microsoft.Extensions.Logging;

namespace ColaFlow.Modules.Identity.Application.Commands.VerifyEmail;

public class VerifyEmailCommandHandler : IRequestHandler<VerifyEmailCommand, bool>
{
    private readonly IEmailVerificationTokenRepository _tokenRepository;
    private readonly IUserRepository _userRepository;
    private readonly ISecurityTokenService _tokenService;
    private readonly ILogger<VerifyEmailCommandHandler> _logger;

    public VerifyEmailCommandHandler(
        IEmailVerificationTokenRepository tokenRepository,
        IUserRepository userRepository,
        ISecurityTokenService tokenService,
        ILogger<VerifyEmailCommandHandler> logger)
    {
        _tokenRepository = tokenRepository;
        _userRepository = userRepository;
        _tokenService = tokenService;
        _logger = logger;
    }

    public async Task<bool> Handle(VerifyEmailCommand request, CancellationToken cancellationToken)
    {
        // Hash the token to look it up
        var tokenHash = _tokenService.HashToken(request.Token);
        var verificationToken = await _tokenRepository.GetByTokenHashAsync(tokenHash, cancellationToken);

        if (verificationToken == null)
        {
            _logger.LogWarning("Email verification token not found");
            return false;
        }

        if (!verificationToken.IsValid)
        {
            _logger.LogWarning(
                "Email verification token is invalid. IsExpired: {IsExpired}, IsVerified: {IsVerified}",
                verificationToken.IsExpired,
                verificationToken.IsVerified);
            return false;
        }

        // Get user and mark email as verified
        var user = await _userRepository.GetByIdAsync(verificationToken.UserId, cancellationToken);
        if (user == null)
        {
            _logger.LogError("User {UserId} not found for email verification", verificationToken.UserId);
            return false;
        }

        // Mark token as verified
        verificationToken.MarkAsVerified();
        await _tokenRepository.UpdateAsync(verificationToken, cancellationToken);

        // Mark user email as verified (will emit domain event)
        user.VerifyEmail();
        await _userRepository.UpdateAsync(user, cancellationToken);

        _logger.LogInformation("Email verified for user {UserId}", user.Id);

        return true;
    }
}
