package com.social.media.util;

import com.social.media.dto.UserCredentialsDto;
import com.social.media.service.UserCredentialsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 * Utility class to help with password management and user creation for testing
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class PasswordTestHelper {
    
    private final UserCredentialsService userCredentialsService;
    private final PasswordEncoder passwordEncoder;
    
    /**
     * Creates a test user with encrypted password for demonstration
     * Note: This method only creates credentials, not the actual user
     */
    public UserCredentialsDto createTestUserWithEncryptedPassword(Long userId, String password) {
        log.info("Creating test credentials for user ID: {} with encrypted password", userId);
        
        try {
            // 1. Validate password strength
            validatePasswordStrength(password);
            
            // 2. Create encrypted credentials
            UserCredentialsDto credentials = createEncryptedCredentials(userId, password);
            
            log.info("Successfully created test credentials for user ID: {} with encrypted password", userId);
            return credentials;
            
        } catch (Exception e) {
            log.error("Failed to create test credentials with encrypted password", e);
            throw new RuntimeException("Failed to create test credentials: " + e.getMessage(), e);
        }
    }
    
    /**
     * Creates encrypted credentials for an existing user
     */
    public UserCredentialsDto createEncryptedCredentials(Long userId, String rawPassword) {
        log.info("Creating encrypted credentials for user ID: {}", userId);
        
        // Validate password
        validatePasswordStrength(rawPassword);
        
        // Create credentials DTO
        UserCredentialsDto credentialsDto = new UserCredentialsDto();
        credentialsDto.setUserId(userId);
        credentialsDto.setPasswordHash(rawPassword); // Service will encrypt this
        credentialsDto.setTwoFactorEnabled(false);
        // Note: EmailVerified is not available in DTO - this will be handled by the entity
        credentialsDto.setFailedLoginAttempts(0);
        credentialsDto.setMaxFailedAttempts(5);
        credentialsDto.setLockoutDurationMinutes(30);
        credentialsDto.setIsAccountLocked(false);
        credentialsDto.setIsPermanentlyLocked(false);
        credentialsDto.setPasswordChangedAt(LocalDateTime.now());
        
        // Create credentials (password will be encrypted by the service)
        UserCredentialsDto created = userCredentialsService.create(credentialsDto);
        
        log.info("Successfully created encrypted credentials for user ID: {}", userId);
        return created;
    }
    
    /**
     * Demonstrates the complete authentication flow
     */
    public boolean demonstrateAuthentication(Long userId, String rawPassword) {
        log.info("Demonstrating authentication for user ID: {} with provided password", userId);
        
        // 1. Show password analysis
        analyzePassword(rawPassword);
        
        // 2. Attempt authentication
        boolean authResult = userCredentialsService.authenticate(userId, rawPassword);
        
        log.info("Authentication result for user ID {}: {}", userId, authResult);
        return authResult;
    }
    
    /**
     * Analyzes password strength and policy compliance
     */
    public void analyzePassword(String password) {
        log.info("Analyzing password strength and policy compliance");
        
        System.out.println("=== ANÁLISE DA SENHA ===");
        System.out.println("Senha: " + password);
        
        // Check policy compliance
        boolean meetsPolicy = userCredentialsService.meetsPasswordPolicy(password);
        System.out.println("Atende à política: " + meetsPolicy);
        
        // Get strength score
        int strengthScore = userCredentialsService.getPasswordStrengthScore(password);
        System.out.println("Pontuação de força: " + strengthScore + "/100");
        
        // Check if strong
        boolean isStrong = userCredentialsService.isPasswordStrong(password);
        System.out.println("É considerada forte: " + isStrong);
        
        // Show policy violations if any
        var violations = userCredentialsService.getPasswordPolicyViolations(password);
        if (violations.isEmpty()) {
            System.out.println("✅ Nenhuma violação de política");
        } else {
            System.out.println("❌ Violações encontradas:");
            violations.forEach(violation -> System.out.println("  - " + violation));
        }
        
        // Show encrypted hash example
        String encryptedHash = passwordEncoder.encode(password);
        System.out.println("Hash criptografado: " + encryptedHash);
        
        // Verify the hash works
        boolean hashVerifies = passwordEncoder.matches(password, encryptedHash);
        System.out.println("Hash verifica corretamente: " + hashVerifies);
        
        System.out.println("========================");
    }
    
    /**
     * Validates password strength and throws exception if weak
     */
    private void validatePasswordStrength(String password) {
        if (!userCredentialsService.meetsPasswordPolicy(password)) {
            var violations = userCredentialsService.getPasswordPolicyViolations(password);
            throw new IllegalArgumentException("Password does not meet policy requirements: " + 
                                             String.join(", ", violations));
        }
        
        if (!userCredentialsService.isPasswordStrong(password)) {
            throw new IllegalArgumentException("Password is not strong enough. Score: " + 
                                             userCredentialsService.getPasswordStrengthScore(password) + "/100");
        }
    }
    
    /**
     * Creates multiple hashes of the same password to demonstrate BCrypt salting
     */
    public void demonstrateBCryptSalting(String password) {
        System.out.println("\n=== DEMONSTRAÇÃO DO SALT DO BCRYPT ===");
        System.out.println("Senha original: " + password);
        
        for (int i = 1; i <= 5; i++) {
            String hash = passwordEncoder.encode(password);
            boolean matches = passwordEncoder.matches(password, hash);
            
            System.out.println("Hash " + i + ": " + hash);
            System.out.println("  Verifica: " + matches);
        }
        
        System.out.println("\n💡 Observe que todos os hashes são diferentes devido ao salt único,");
        System.out.println("   mas todos verificam corretamente contra a senha original!");
    }
    
    /**
     * Shows the complete encryption and authentication process
     */
    public void demonstrateCompleteProcess(String password) {
        System.out.println("\n=== PROCESSO COMPLETO DE CRIPTOGRAFIA E AUTENTICAÇÃO ===");
        
        // 1. Analyze password
        analyzePassword(password);
        
        // 2. Show encryption process
        System.out.println("\n1. PROCESSO DE CRIPTOGRAFIA:");
        String hash = passwordEncoder.encode(password);
        System.out.println("   Senha original: " + password);
        System.out.println("   Hash gerado: " + hash);
        
        // 3. Show storage simulation
        System.out.println("\n2. SIMULAÇÃO DE ARMAZENAMENTO:");
        System.out.println("   ✅ Hash salvo no banco de dados");
        System.out.println("   ❌ Senha original NUNCA é armazenada");
        
        // 4. Show authentication process
        System.out.println("\n3. PROCESSO DE AUTENTICAÇÃO:");
        System.out.println("   Usuário fornece senha: " + password);
        System.out.println("   Sistema busca hash do banco: " + hash);
        
        boolean authSuccess = passwordEncoder.matches(password, hash);
        System.out.println("   BCrypt compara senha com hash: " + authSuccess);
        
        // 5. Test with wrong password
        String wrongPassword = "senhaIncorreta123";
        boolean wrongAuth = passwordEncoder.matches(wrongPassword, hash);
        System.out.println("   Teste com senha incorreta (" + wrongPassword + "): " + wrongAuth);
        
        System.out.println("\n✅ PROCESSO DEMONSTRADO COM SUCESSO!");
    }
}
