using ColaFlow.Modules.Identity.Application.Services;
using ColaFlow.Modules.Identity.Domain.Aggregates.Tenants;
using ColaFlow.Modules.Identity.Domain.Aggregates.Users;
using ColaFlow.Modules.Identity.Domain.Entities;
using ColaFlow.Modules.Identity.Domain.Repositories;
using ColaFlow.Modules.Identity.Domain.Services;
using MediatR;
using Microsoft.Extensions.Logging;

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

/// <summary>
/// Handler for resending email verification link
/// Implements security best practices:
/// - Email enumeration prevention (always returns true)
/// - Rate limiting (1 email per minute)
/// - Token rotation (invalidate old token)
/// </summary>
public class ResendVerificationEmailCommandHandler : IRequestHandler<ResendVerificationEmailCommand, bool>
{
    private readonly IUserRepository _userRepository;
    private readonly IEmailVerificationTokenRepository _tokenRepository;
    private readonly ISecurityTokenService _tokenService;
    private readonly IEmailService _emailService;
    private readonly IEmailTemplateService _templateService;
    private readonly IRateLimitService _rateLimitService;
    private readonly ILogger<ResendVerificationEmailCommandHandler> _logger;

    public ResendVerificationEmailCommandHandler(
        IUserRepository userRepository,
        IEmailVerificationTokenRepository tokenRepository,
        ISecurityTokenService tokenService,
        IEmailService emailService,
        IEmailTemplateService templateService,
        IRateLimitService rateLimitService,
        ILogger<ResendVerificationEmailCommandHandler> logger)
    {
        _userRepository = userRepository;
        _tokenRepository = tokenRepository;
        _tokenService = tokenService;
        _emailService = emailService;
        _templateService = templateService;
        _rateLimitService = rateLimitService;
        _logger = logger;
    }

    public async Task<bool> Handle(ResendVerificationEmailCommand request, CancellationToken cancellationToken)
    {
        try
        {
            // 1. Find user by email and tenant (no enumeration - don't reveal if user exists)
            var email = Email.Create(request.Email);
            var tenantId = TenantId.Create(request.TenantId);
            var user = await _userRepository.GetByEmailAsync(tenantId, email, cancellationToken);

            if (user == null)
            {
                // Email enumeration prevention: Don't reveal user doesn't exist
                _logger.LogWarning("Resend verification requested for non-existent email: {Email}", request.Email);
                return true; // Always return success
            }

            // 2. Check if already verified (success if so)
            if (user.IsEmailVerified)
            {
                _logger.LogInformation("Email already verified for user {UserId}", user.Id);
                return true; // Already verified - success
            }

            // 3. Check rate limit (1 email per minute per address)
            var rateLimitKey = $"resend-verification:{request.Email}:{request.TenantId}";
            var isAllowed = await _rateLimitService.IsAllowedAsync(
                rateLimitKey,
                maxAttempts: 1,
                window: TimeSpan.FromMinutes(1),
                cancellationToken);

            if (!isAllowed)
            {
                _logger.LogWarning(
                    "Rate limit exceeded for resend verification: {Email}",
                    request.Email);
                return true; // Still return success to prevent enumeration
            }

            // 4. Generate new verification token with SHA-256 hashing
            var token = _tokenService.GenerateToken();
            var tokenHash = _tokenService.HashToken(token);

            // 5. Invalidate old tokens by creating new one (token rotation)
            var verificationToken = EmailVerificationToken.Create(
                UserId.Create(user.Id),
                tokenHash,
                DateTime.UtcNow.AddHours(24)); // 24 hours expiration

            await _tokenRepository.AddAsync(verificationToken, cancellationToken);

            // 6. Send verification email
            var verificationLink = $"{request.BaseUrl}/verify-email?token={token}";
            var htmlBody = _templateService.RenderVerificationEmail(user.FullName.Value, verificationLink);

            var emailMessage = new EmailMessage(
                To: request.Email,
                Subject: "Verify your email address - ColaFlow",
                HtmlBody: htmlBody,
                PlainTextBody: $"Click the link to verify your email: {verificationLink}");

            var success = await _emailService.SendEmailAsync(emailMessage, cancellationToken);

            if (!success)
            {
                _logger.LogWarning(
                    "Failed to send verification email to {Email} for user {UserId}",
                    request.Email,
                    user.Id);
            }
            else
            {
                _logger.LogInformation(
                    "Verification email resent to {Email} for user {UserId}",
                    request.Email,
                    user.Id);
            }

            // 7. Always return success (prevent email enumeration)
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(
                ex,
                "Error resending verification email for {Email}",
                request.Email);

            // Return true even on error to prevent enumeration
            return true;
        }
    }
}
