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(
    IUserRepository userRepository,
    IEmailVerificationTokenRepository tokenRepository,
    ISecurityTokenService tokenService,
    IEmailService emailService,
    IEmailTemplateService templateService,
    IRateLimitService rateLimitService,
    ILogger<ResendVerificationEmailCommandHandler> logger)
    : IRequestHandler<ResendVerificationEmailCommand, bool>
{
    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;
        }
    }
}
