package com.social.media.service.impl;

import com.social.media.dto.LoginRequest;
import com.social.media.dto.LoginResponse;
import com.social.media.dto.UserDto;
import com.social.media.dto.UserCredentialsDto;
import com.social.media.service.AuthService;
import com.social.media.service.UserService;
import com.social.media.service.UserCredentialsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Optional;

/**
 * Implementation of AuthService for user authentication
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class AuthServiceImpl implements AuthService {

    private final UserService userService;
    private final UserCredentialsService userCredentialsService;
    // private final JwtTokenProvider jwtTokenProvider; // Descomente se implementar JWT

    @Override
    @Transactional
    public LoginResponse authenticate(LoginRequest loginRequest) {
        log.info("Tentativa de login para email: {}", loginRequest.getEmail());
        
        try {
            // 1. Buscar usuário por email
            Optional<UserDto> userOptional = userService.findByEmail(loginRequest.getEmail());
            if (userOptional.isEmpty()) {
                log.warn("Usuário não encontrado para email: {}", loginRequest.getEmail());
                return LoginResponse.error("Email ou senha inválidos");
            }
            
            UserDto user = userOptional.get();
            
            // 2. Verificar se o usuário está ativo
            if (!isUserActive(user)) {
                log.warn("Tentativa de login com usuário inativo: {}", user.getEmail());
                return LoginResponse.error("Conta inativa ou bloqueada");
            }
            
            // 3. Buscar credenciais do usuário
            Optional<UserCredentialsDto> credentialsOptional = userCredentialsService.findByUserId(user.getId());
            if (credentialsOptional.isEmpty()) {
                log.error("Credenciais não encontradas para usuário: {}", user.getId());
                return LoginResponse.error("Erro interno - credenciais não encontradas");
            }
            
            UserCredentialsDto credentials = credentialsOptional.get();
            
            // 4. Verificar se a conta está bloqueada
            if (userCredentialsService.isAccountLocked(user.getId())) {
                log.warn("Tentativa de login com conta bloqueada: {}", user.getEmail());
                String lockMessage = buildLockMessage(credentials);
                return LoginResponse.accountLocked(lockMessage);
            }
            
            // 5. Verificar senha usando o método authenticate do UserCredentialsService
            if (!userCredentialsService.authenticate(user.getId(), loginRequest.getPassword())) {
                log.warn("Senha incorreta para usuário: {}", user.getEmail());
                
                // O método authenticate já registra tentativas falhadas internamente
                
                // Verificar se a conta deve ser bloqueada
                Optional<UserCredentialsDto> updatedCredentials = userCredentialsService.findByUserId(user.getId());
                if (updatedCredentials.isPresent() && updatedCredentials.get().getIsAccountLocked()) {
                    String lockMessage = buildLockMessage(updatedCredentials.get());
                    return LoginResponse.accountLocked(lockMessage);
                }
                
                return LoginResponse.error("Email ou senha inválidos");
            }
            
            // 6. Verificar se a senha expirou (política de 90 dias)
            if (isPasswordExpired(credentials)) {
                log.info("Senha expirada para usuário: {}", user.getEmail());
                Integer daysUntilExpiry = getDaysUntilPasswordExpiry(credentials);
                return LoginResponse.passwordExpired(user, daysUntilExpiry);
            }
            
            // 7. Login bem-sucedido
            log.info("Login bem-sucedido para usuário: {}", user.getEmail());
            
            // Registrar login bem-sucedido
            userCredentialsService.recordSuccessfulLogin(user.getId());
            
            // Atualizar último acesso do usuário
            userService.updateLastAccess(user.getId());
            
            // Gerar token JWT (se implementado)
            String token = generateAuthToken(user);
            
            // Construir resposta de sucesso
            LoginResponse response = LoginResponse.success(user, token);
            
            // Adicionar informações de segurança
            response.setTwoFactorEnabled(credentials.getTwoFactorEnabled());
            response.setPasswordExpired(false);
            response.setAccountLocked(false);
            response.setDaysUntilPasswordExpiry(getDaysUntilPasswordExpiry(credentials));
            
            return response;
            
        } catch (Exception e) {
            log.error("Erro durante autenticação para email: {}", loginRequest.getEmail(), e);
            return LoginResponse.error("Erro interno durante autenticação");
        }
    }
    
    @Override
    public boolean logout(Long userId) {
        try {
            log.info("Logout para usuário: {}", userId);
            // Implementar invalidação de token/sessão se necessário
            // Por exemplo, adicionar token a uma blacklist
            return true;
        } catch (Exception e) {
            log.error("Erro durante logout para usuário: {}", userId, e);
            return false;
        }
    }
    
    @Override
    public boolean validateSession(Long userId, String token) {
        try {
            // Implementar validação de sessão/token se necessário
            // Por exemplo, verificar se o token é válido e não está na blacklist
            return true;
        } catch (Exception e) {
            log.error("Erro durante validação de sessão para usuário: {}", userId, e);
            return false;
        }
    }
    
    @Override
    public String refreshToken(String refreshToken) {
        try {
            // Implementar refresh de token se necessário
            // Por exemplo, validar refresh token e gerar novo access token
            return null;
        } catch (Exception e) {
            log.error("Erro durante refresh de token", e);
            return null;
        }
    }
    
    /**
     * Verifica se o usuário está ativo e pode fazer login
     */
    private boolean isUserActive(UserDto user) {
        if (user.getDeleted() != null && user.getDeleted()) {
            return false;
        }
        
        if (user.getStatus() == null) {
            return false;
        }
        
        // Permitir login apenas para usuários ACTIVE
        return "ACTIVE".equals(user.getStatus());
    }
    
    /**
     * Verifica se a senha expirou (política de 90 dias)
     */
    private boolean isPasswordExpired(UserCredentialsDto credentials) {
        if (credentials.getPasswordChangedAt() == null) {
            // Se nunca alterou a senha, considera expirada
            return true;
        }
        
        LocalDateTime expiryDate = credentials.getPasswordChangedAt().plusDays(90);
        return LocalDateTime.now().isAfter(expiryDate);
    }
    
    /**
     * Calcula quantos dias restam até a senha expirar
     */
    private Integer getDaysUntilPasswordExpiry(UserCredentialsDto credentials) {
        if (credentials.getPasswordChangedAt() == null) {
            return 0;
        }
        
        LocalDateTime expiryDate = credentials.getPasswordChangedAt().plusDays(90);
        LocalDateTime now = LocalDateTime.now();
        
        if (expiryDate.isBefore(now)) {
            return 0; // Já expirou
        }
        
        return (int) java.time.Duration.between(now, expiryDate).toDays();
    }
    
    /**
     * Constrói mensagem informativa sobre bloqueio da conta
     */
    private String buildLockMessage(UserCredentialsDto credentials) {
        if (credentials.getIsPermanentlyLocked() != null && credentials.getIsPermanentlyLocked()) {
            return "Conta permanentemente bloqueada. Entre em contato com o administrador.";
        }
        
        if (credentials.getRemainingLockoutMinutes() != null && credentials.getRemainingLockoutMinutes() > 0) {
            long minutes = credentials.getRemainingLockoutMinutes();
            if (minutes < 60) {
                return String.format("Conta temporariamente bloqueada. Tente novamente em %d minutos.", minutes);
            } else {
                long hours = minutes / 60;
                long remainingMinutes = minutes % 60;
                return String.format("Conta temporariamente bloqueada. Tente novamente em %d horas e %d minutos.", 
                                    hours, remainingMinutes);
            }
        }
        
        return "Conta bloqueada devido a múltiplas tentativas de login falhadas.";
    }
    
    /**
     * Gera token de autenticação (JWT ou session ID)
     */
    private String generateAuthToken(UserDto user) {
        // Implementação simples - pode ser substituída por JWT
        // Por exemplo: return jwtTokenProvider.createToken(user.getId(), user.getEmail());
        
        // Por enquanto, retorna um token simples baseado no tempo e ID do usuário
        long timestamp = System.currentTimeMillis();
        return String.format("AUTH_%d_%d", user.getId(), timestamp);
    }
}
