package dev.lions.user.manager.service.impl;

import dev.lions.user.manager.server.impl.interceptor.Logged;

import dev.lions.user.manager.client.KeycloakAdminClient;
import dev.lions.user.manager.dto.importexport.ImportResultDTO;
import dev.lions.user.manager.dto.user.UserDTO;
import dev.lions.user.manager.dto.user.UserSearchCriteriaDTO;
import dev.lions.user.manager.dto.user.UserSearchResultDTO;
import dev.lions.user.manager.enums.user.StatutUser;
import dev.lions.user.manager.mapper.UserMapper;
import dev.lions.user.manager.service.UserService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.NotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Implémentation du service de gestion des utilisateurs
 * Utilise UNIQUEMENT l'API Admin Keycloak (ZERO accès direct à la DB Keycloak)
 */
@ApplicationScoped
@Slf4j
public class UserServiceImpl implements UserService {

    @Inject
    KeycloakAdminClient keycloakAdminClient;

    @Override
    public UserSearchResultDTO searchUsers(@Valid @NotNull UserSearchCriteriaDTO criteria) {
        log.info("Recherche d'utilisateurs avec critères: {}", criteria);

        try {
            String realmName = criteria.getRealmName();
            UsersResource usersResource = keycloakAdminClient.getUsers(realmName);

            // Construire la requête de recherche
            List<UserRepresentation> users;

            if (criteria.getSearchTerm() != null && !criteria.getSearchTerm().isBlank()) {
                // Recherche globale
                users = usersResource.search(
                        criteria.getSearchTerm(),
                        criteria.getOffset(),
                        criteria.getPageSize());
            } else if (criteria.getUsername() != null) {
                // Recherche par username exact
                users = usersResource.search(
                        criteria.getUsername(),
                        criteria.getOffset(),
                        criteria.getPageSize(),
                        true // exact match
                );
            } else if (criteria.getEmail() != null) {
                // Recherche par email
                users = usersResource.searchByEmail(
                        criteria.getEmail(),
                        true // exact match
                );
            } else {
                // Liste tous les utilisateurs
                users = usersResource.list(
                        criteria.getOffset(),
                        criteria.getPageSize());
            }

            // Filtrer selon les critères supplémentaires
            users = filterUsers(users, criteria);

            // Convertir en DTOs
            List<UserDTO> userDTOs = UserMapper.toDTOList(users, realmName);

            // Enrichir avec les rôles si demandé
            if (Boolean.TRUE.equals(criteria.getIncludeRoles())) {
                for (UserDTO dto : userDTOs) {
                    try {
                        List<RoleRepresentation> realmRoles = usersResource.get(dto.getId())
                                .roles().realmLevel().listAll();
                        if (realmRoles != null) {
                            dto.setRealmRoles(realmRoles.stream()
                                    .map(RoleRepresentation::getName)
                                    .collect(Collectors.toList()));
                        }
                    } catch (Exception e) {
                        log.warn("Impossible de charger les rôles pour l'utilisateur {}: {}", dto.getId(), e.getMessage());
                    }
                }
            }

            // Compter le total
            long totalCount = usersResource.count();

            // Construire le résultat paginé
            return UserSearchResultDTO.of(userDTOs, criteria, totalCount);

        } catch (Exception e) {
            log.error("Erreur lors de la recherche d'utilisateurs", e);
            throw new RuntimeException("Impossible de rechercher les utilisateurs", e);
        }
    }

    @Override
    public Optional<UserDTO> getUserById(@NotBlank String userId, @NotBlank String realmName) {
        log.info("Récupération de l'utilisateur {} dans le realm {}", userId, realmName);

        try {
            UserResource userResource = keycloakAdminClient.getUsers(realmName).get(userId);
            UserRepresentation userRep = userResource.toRepresentation();
            UserDTO userDTO = UserMapper.toDTO(userRep, realmName);

            // Récupérer les rôles realm de l'utilisateur
            try {
                List<RoleRepresentation> realmRoles = userResource.roles().realmLevel().listAll();
                if (realmRoles != null && !realmRoles.isEmpty()) {
                    List<String> roleNames = realmRoles.stream()
                            .map(RoleRepresentation::getName)
                            .collect(Collectors.toList());
                    userDTO.setRealmRoles(roleNames);
                }
            } catch (Exception e) {
                log.warn("Erreur lors de la récupération des rôles realm pour l'utilisateur {}: {}", userId,
                        e.getMessage());
                // Ne pas échouer si les rôles ne peuvent pas être récupérés
            }

            return Optional.of(userDTO);
        } catch (NotFoundException e) {
            log.warn("Utilisateur {} non trouvé dans le realm {}", userId, realmName);
            return Optional.empty();
        } catch (Exception e) {
            // Vérifier si l'exception contient un message indiquant un 404
            String errorMessage = e.getMessage();
            if (errorMessage != null && (errorMessage.contains("404") ||
                    errorMessage.contains("Server response is: 404") ||
                    errorMessage.contains("Received: 'Server response is: 404'"))) {
                log.warn("Utilisateur {} non trouvé dans le realm {} (404 détecté dans l'exception)", userId,
                        realmName);
                return Optional.empty();
            }
            log.error("Erreur lors de la récupération de l'utilisateur {}", userId, e);
            throw new RuntimeException("Impossible de récupérer l'utilisateur", e);
        }
    }

    @Override
    public Optional<UserDTO> getUserByUsername(@NotBlank String username, @NotBlank String realmName) {
        log.info("Récupération de l'utilisateur par username {} dans le realm {}", username, realmName);

        try {
            List<UserRepresentation> users = keycloakAdminClient.getUsers(realmName)
                    .search(username, 0, 1, true);

            if (users.isEmpty()) {
                return Optional.empty();
            }

            return Optional.of(UserMapper.toDTO(users.get(0), realmName));
        } catch (Exception e) {
            log.error("Erreur lors de la récupération de l'utilisateur par username {}", username, e);
            throw new RuntimeException("Impossible de récupérer l'utilisateur", e);
        }
    }

    @Override
    public Optional<UserDTO> getUserByEmail(@NotBlank String email, @NotBlank String realmName) {
        log.info("Récupération de l'utilisateur par email {} dans le realm {}", email, realmName);

        try {
            List<UserRepresentation> users = keycloakAdminClient.getUsers(realmName)
                    .searchByEmail(email, true);

            if (users.isEmpty()) {
                return Optional.empty();
            }

            return Optional.of(UserMapper.toDTO(users.get(0), realmName));
        } catch (Exception e) {
            log.error("Erreur lors de la récupération de l'utilisateur par email {}", email, e);
            throw new RuntimeException("Impossible de récupérer l'utilisateur", e);
        }
    }

    @Override
    @Logged(action = "USER_CREATE", resource = "USER")
    public UserDTO createUser(@Valid @NotNull UserDTO user, @NotBlank String realmName) {
        log.info("Création de l'utilisateur {} dans le realm {}", user.getUsername(), realmName);

        try {
            // Vérifier si l'utilisateur existe déjà
            if (usernameExists(user.getUsername(), realmName)) {
                throw new IllegalArgumentException("Le nom d'utilisateur existe déjà: " + user.getUsername());
            }

            if (user.getEmail() != null && emailExists(user.getEmail(), realmName)) {
                throw new IllegalArgumentException("L'email existe déjà: " + user.getEmail());
            }

            // Convertir DTO vers UserRepresentation
            UserRepresentation userRep = UserMapper.toRepresentation(user);

            // Créer l'utilisateur
            UsersResource usersResource = keycloakAdminClient.getUsers(realmName);
            var response = usersResource.create(userRep);

            if (response.getStatus() != 201) {
                throw new RuntimeException("Échec de la création de l'utilisateur: " + response.getStatusInfo());
            }

            // Récupérer l'ID de l'utilisateur créé
            String userId = response.getLocation().getPath().replaceAll(".*/([^/]+)$", "$1");

            // Définir le mot de passe si fourni
            if (user.getTemporaryPassword() != null) {
                setPassword(userId, realmName, user.getTemporaryPassword(),
                        user.getTemporaryPasswordFlag() != null && user.getTemporaryPasswordFlag());
            }

            // Récupérer l'utilisateur créé
            UserResource userResource = usersResource.get(userId);
            UserRepresentation createdUser = userResource.toRepresentation();

            log.info("✅ Utilisateur créé avec succès: {} (ID: {})", user.getUsername(), userId);
            return UserMapper.toDTO(createdUser, realmName);

        } catch (Exception e) {
            log.error("❌ Erreur lors de la création de l'utilisateur {}", user.getUsername(), e);
            throw new RuntimeException("Impossible de créer l'utilisateur", e);
        }
    }

    @Override
    @Logged(action = "USER_UPDATE", resource = "USER")
    public UserDTO updateUser(@NotBlank String userId, @Valid @NotNull UserDTO user, @NotBlank String realmName) {
        log.info("Mise à jour de l'utilisateur {} dans le realm {}", userId, realmName);

        try {
            UserResource userResource = keycloakAdminClient.getUsers(realmName).get(userId);

            // Récupérer l'utilisateur existant
            UserRepresentation existingUser = userResource.toRepresentation();

            // Mettre à jour les champs
            if (user.getEmail() != null) {
                existingUser.setEmail(user.getEmail());
            }
            if (user.getPrenom() != null) {
                existingUser.setFirstName(user.getPrenom());
            }
            if (user.getNom() != null) {
                existingUser.setLastName(user.getNom());
            }
            if (user.getEnabled() != null) {
                existingUser.setEnabled(user.getEnabled());
            }
            if (user.getEmailVerified() != null) {
                existingUser.setEmailVerified(user.getEmailVerified());
            }
            if (user.getAttributes() != null) {
                existingUser.setAttributes(user.getAttributes());
            }

            // Envoyer la mise à jour
            userResource.update(existingUser);

            // Récupérer l'utilisateur mis à jour
            UserRepresentation updatedUser = userResource.toRepresentation();

            log.info("✅ Utilisateur mis à jour avec succès: {}", userId);
            return UserMapper.toDTO(updatedUser, realmName);

        } catch (NotFoundException e) {
            log.error("❌ Utilisateur {} non trouvé", userId);
            throw new RuntimeException("Utilisateur non trouvé", e);
        } catch (Exception e) {
            log.error("❌ Erreur lors de la mise à jour de l'utilisateur {}", userId, e);
            throw new RuntimeException("Impossible de mettre à jour l'utilisateur", e);
        }
    }

    @Override
    @Logged(action = "USER_DELETE", resource = "USER")
    public void deleteUser(@NotBlank String userId, @NotBlank String realmName, boolean hardDelete) {
        log.info("Suppression de l'utilisateur {} dans le realm {} (hard: {})", userId, realmName, hardDelete);

        try {
            UserResource userResource = keycloakAdminClient.getUsers(realmName).get(userId);

            if (hardDelete) {
                // Suppression définitive
                userResource.remove();
                log.info("✅ Utilisateur supprimé définitivement: {}", userId);
            } else {
                // Soft delete: désactiver l'utilisateur
                UserRepresentation user = userResource.toRepresentation();
                user.setEnabled(false);
                userResource.update(user);
                log.info("✅ Utilisateur désactivé (soft delete): {}", userId);
            }

        } catch (NotFoundException e) {
            log.error("❌ Utilisateur {} non trouvé", userId);
            throw new RuntimeException("Utilisateur non trouvé", e);
        } catch (Exception e) {
            log.error("❌ Erreur lors de la suppression de l'utilisateur {}", userId, e);
            throw new RuntimeException("Impossible de supprimer l'utilisateur", e);
        }
    }

    @Override
    @Logged(action = "USER_ACTIVATE", resource = "USER")
    public void activateUser(@NotBlank String userId, @NotBlank String realmName) {
        log.info("Activation de l'utilisateur {} dans le realm {}", userId, realmName);

        try {
            UserResource userResource = keycloakAdminClient.getUsers(realmName).get(userId);
            UserRepresentation user = userResource.toRepresentation();
            user.setEnabled(true);
            userResource.update(user);

            log.info("✅ Utilisateur activé: {}", userId);
        } catch (Exception e) {
            log.error("❌ Erreur lors de l'activation de l'utilisateur {}", userId, e);
            throw new RuntimeException("Impossible d'activer l'utilisateur", e);
        }
    }

    @Override
    @Logged(action = "USER_DEACTIVATE", resource = "USER")
    public void deactivateUser(@NotBlank String userId, @NotBlank String realmName, String raison) {
        log.info("Désactivation de l'utilisateur {} dans le realm {} (raison: {})", userId, realmName, raison);

        try {
            UserResource userResource = keycloakAdminClient.getUsers(realmName).get(userId);
            UserRepresentation user = userResource.toRepresentation();
            user.setEnabled(false);
            userResource.update(user);

            log.info("✅ Utilisateur désactivé: {}", userId);
        } catch (Exception e) {
            log.error("❌ Erreur lors de la désactivation de l'utilisateur {}", userId, e);
            throw new RuntimeException("Impossible de désactiver l'utilisateur", e);
        }
    }

    @Override
    public void suspendUser(@NotBlank String userId, @NotBlank String realmName, String raison, int duree) {
        log.info("Suspension de l'utilisateur {} dans le realm {} (raison: {}, durée: {} jours)",
                userId, realmName, raison, duree);

        deactivateUser(userId, realmName, raison);
    }

    @Override
    @Logged(action = "USER_UNLOCK", resource = "USER")
    public void unlockUser(@NotBlank String userId, @NotBlank String realmName) {
        log.info("Déverrouillage de l'utilisateur {} dans le realm {}", userId, realmName);
        activateUser(userId, realmName);
    }

    @Override
    @Logged(action = "USER_PASSWORD_RESET", resource = "USER")
    public void resetPassword(@NotBlank String userId, @NotBlank String realmName,
            @NotBlank String temporaryPassword, boolean temporary) {
        log.info("Réinitialisation du mot de passe pour l'utilisateur {} (temporaire: {})", userId, temporary);

        setPassword(userId, realmName, temporaryPassword, temporary);
    }

    @Override
    public void sendVerificationEmail(@NotBlank String userId, @NotBlank String realmName) {
        log.info("Envoi d'un email de vérification à l'utilisateur {}", userId);

        try {
            UserResource userResource = keycloakAdminClient.getUsers(realmName).get(userId);
            userResource.sendVerifyEmail();

            log.info("✅ Email de vérification envoyé: {}", userId);
        } catch (Exception e) {
            log.error("❌ Erreur lors de l'envoi de l'email de vérification pour {}", userId, e);
            throw new RuntimeException("Impossible d'envoyer l'email de vérification", e);
        }
    }

    @Override
    @Logged(action = "USER_FORCE_LOGOUT", resource = "USER")
    public int logoutAllSessions(@NotBlank String userId, @NotBlank String realmName) {
        log.info("Déconnexion de toutes les sessions pour l'utilisateur {}", userId);

        try {
            UserResource userResource = keycloakAdminClient.getUsers(realmName).get(userId);
            int sessionsCount = userResource.getUserSessions().size();
            userResource.logout();

            log.info("✅ {} sessions révoquées pour l'utilisateur {}", sessionsCount, userId);
            return sessionsCount;
        } catch (Exception e) {
            log.error("❌ Erreur lors de la déconnexion des sessions pour {}", userId, e);
            throw new RuntimeException("Impossible de déconnecter les sessions", e);
        }
    }

    @Override
    public List<String> getActiveSessions(@NotBlank String userId, @NotBlank String realmName) {
        log.info("Récupération des sessions actives pour l'utilisateur {}", userId);

        try {
            UserResource userResource = keycloakAdminClient.getUsers(realmName).get(userId);
            return userResource.getUserSessions().stream()
                    .map(session -> session.getId())
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("❌ Erreur lors de la récupération des sessions pour {}", userId, e);
            return Collections.emptyList();
        }
    }

    @Override
    public long countUsers(@NotNull UserSearchCriteriaDTO criteria) {
        try {
            return keycloakAdminClient.getUsers(criteria.getRealmName()).count();
        } catch (Exception e) {
            log.error("Erreur lors du comptage des utilisateurs", e);
            return 0;
        }
    }

    @Override
    public UserSearchResultDTO getAllUsers(@NotBlank String realmName, int page, int pageSize) {
        UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder()
                .realmName(realmName)
                .page(page)
                .pageSize(pageSize)
                .build();

        return searchUsers(criteria);
    }

    @Override
    public boolean usernameExists(@NotBlank String username, @NotBlank String realmName) {
        try {
            List<UserRepresentation> users = keycloakAdminClient.getUsers(realmName)
                    .search(username, 0, 1, true);
            return !users.isEmpty();
        } catch (Exception e) {
            log.error("Erreur lors de la vérification de l'existence du username {}", username, e);
            return false;
        }
    }

    @Override
    public boolean emailExists(@NotBlank String email, @NotBlank String realmName) {
        try {
            List<UserRepresentation> users = keycloakAdminClient.getUsers(realmName)
                    .searchByEmail(email, true);
            return !users.isEmpty();
        } catch (Exception e) {
            log.error("Erreur lors de la vérification de l'existence de l'email {}", email, e);
            return false;
        }
    }

    @Override
    public String exportUsersToCSV(@NotNull UserSearchCriteriaDTO criteria) {
        log.info("Export CSV des utilisateurs avec critères: {}", criteria);

        try {
            // Récupérer tous les utilisateurs correspondant aux critères
            UserSearchResultDTO searchResult = searchUsers(criteria);
            List<UserDTO> users = searchResult.getUsers();

            if (users == null || users.isEmpty()) {
                log.warn("Aucun utilisateur trouvé pour l'export CSV");
                return generateCSVHeader();
            }

            // Générer le CSV
            StringBuilder csv = new StringBuilder();
            csv.append(generateCSVHeader());
            csv.append("\n");

            for (UserDTO user : users) {
                csv.append(escapeCSVField(user.getUsername() != null ? user.getUsername() : ""));
                csv.append(",");
                csv.append(escapeCSVField(user.getEmail() != null ? user.getEmail() : ""));
                csv.append(",");
                csv.append(escapeCSVField(user.getPrenom() != null ? user.getPrenom() : ""));
                csv.append(",");
                csv.append(escapeCSVField(user.getNom() != null ? user.getNom() : ""));
                csv.append(",");
                csv.append(escapeCSVField(user.getTelephone() != null ? user.getTelephone() : ""));
                csv.append(",");
                csv.append(user.getEnabled() != null && user.getEnabled() ? "true" : "false");
                csv.append(",");
                csv.append(user.getEmailVerified() != null && user.getEmailVerified() ? "true" : "false");
                csv.append(",");
                csv.append(escapeCSVField(user.getStatut() != null ? user.getStatut().name() : ""));
                csv.append(",");
                csv.append(escapeCSVField(user.getOrganisation() != null ? user.getOrganisation() : ""));
                csv.append(",");
                csv.append(escapeCSVField(user.getDepartement() != null ? user.getDepartement() : ""));
                csv.append(",");
                csv.append(escapeCSVField(user.getFonction() != null ? user.getFonction() : ""));
                csv.append(",");
                csv.append(escapeCSVField(user.getPays() != null ? user.getPays() : ""));
                csv.append(",");
                csv.append(escapeCSVField(user.getVille() != null ? user.getVille() : ""));
                csv.append(",");
                csv.append(escapeCSVField(user.getDateCreation() != null
                        ? user.getDateCreation().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
                        : ""));
                csv.append("\n");
            }

            log.info("✅ Export CSV réussi: {} utilisateur(s) exporté(s)", users.size());
            return csv.toString();

        } catch (Exception e) {
            log.error("❌ Erreur lors de l'export CSV", e);
            throw new RuntimeException("Impossible d'exporter les utilisateurs en CSV", e);
        }
    }

    private String generateCSVHeader() {
        return "username,email,prenom,nom,telephone,enabled,emailVerified,statut,organisation,departement,fonction,pays,ville,dateCreation";
    }

    private String escapeCSVField(String field) {
        if (field == null) {
            return "";
        }
        // Si le champ contient une virgule, des guillemets ou un saut de ligne,
        // l'entourer de guillemets
        if (field.contains(",") || field.contains("\"") || field.contains("\n")) {
            // Échapper les guillemets en les doublant
            return "\"" + field.replace("\"", "\"\"") + "\"";
        }
        return field;
    }

    @Override
    @Logged(action = "USER_IMPORT", resource = "USER")
    public ImportResultDTO importUsersFromCSV(@NotBlank String csvContent, @NotBlank String realmName) {
        log.info("Import CSV de {} lignes pour le realm {}", csvContent.split("\n").length, realmName);

        ImportResultDTO.ImportResultDTOBuilder resultBuilder = ImportResultDTO.builder();
        List<ImportResultDTO.ImportErrorDTO> errors = new ArrayList<>();
        int successCount = 0;
        int lineNumber = 0;

        String[] lines = csvContent.split("\n");
        resultBuilder.totalLines(lines.length);

        // Ignorer la première ligne si c'est l'en-tête
        int startLine = 0;
        if (lines.length > 0 && lines[0].toLowerCase().contains("username")) {
            startLine = 1;
        }

        for (int i = startLine; i < lines.length; i++) {
            lineNumber = i + 1;
            String line = lines[i].trim();

            if (line.isEmpty()) {
                continue;
            }

            try {
                // Parser la ligne CSV
                String[] fields = parseCSVLine(line);

                if (fields.length < 4) {
                    errors.add(ImportResultDTO.ImportErrorDTO.builder()
                            .lineNumber(lineNumber)
                            .lineContent(line)
                            .errorType(ImportResultDTO.ErrorType.INVALID_FORMAT)
                            .message("Nombre de colonnes insuffisant (minimum 4: username, email, prenom, nom)")
                            .build());
                    continue;
                }

                // Créer l'utilisateur
                String username = fields[0].trim();
                String email = fields[1].trim();
                String prenom = fields.length > 2 ? fields[2].trim() : "";
                String nom = fields.length > 3 ? fields[3].trim() : "";
                String telephone = fields.length > 4 ? fields[4].trim() : null;
                Boolean enabled = fields.length > 5 ? Boolean.parseBoolean(fields[5].trim()) : true;
                Boolean emailVerified = fields.length > 6 ? Boolean.parseBoolean(fields[6].trim()) : false;

                // Valider les champs obligatoires
                if (username.isBlank() || email.isBlank()) {
                    errors.add(ImportResultDTO.ImportErrorDTO.builder()
                            .lineNumber(lineNumber)
                            .lineContent(line)
                            .errorType(ImportResultDTO.ErrorType.VALIDATION_ERROR)
                            .field(username.isBlank() ? "username" : "email")
                            .message("Le username et l'email sont obligatoires")
                            .build());
                    continue;
                }

                // Vérifier si l'utilisateur existe déjà
                if (emailExists(email, realmName)) {
                    errors.add(ImportResultDTO.ImportErrorDTO.builder()
                            .lineNumber(lineNumber)
                            .lineContent(line)
                            .errorType(ImportResultDTO.ErrorType.DUPLICATE_USER)
                            .field("email")
                            .message("Un utilisateur avec cet email existe déjà")
                            .build());
                    continue;
                }

                // Créer l'utilisateur
                UserDTO newUser = UserDTO.builder()
                        .username(username)
                        .email(email)
                        .prenom(prenom)
                        .nom(nom)
                        .telephone(telephone)
                        .enabled(enabled)
                        .emailVerified(emailVerified)
                        .build();

                createUser(newUser, realmName);
                successCount++;

            } catch (Exception e) {
                log.error("Erreur lors de l'import de la ligne {}: {}", lineNumber, e.getMessage());
                errors.add(ImportResultDTO.ImportErrorDTO.builder()
                        .lineNumber(lineNumber)
                        .lineContent(line)
                        .errorType(ImportResultDTO.ErrorType.CREATION_ERROR)
                        .message("Erreur lors de la création: " + e.getMessage())
                        .details(e.getClass().getSimpleName())
                        .build());
            }
        }

        resultBuilder.successCount(successCount);
        resultBuilder.errors(errors);
        resultBuilder.errorCount(errors.size());

        ImportResultDTO result = resultBuilder.build();
        result.generateMessage();

        log.info("✅ Import CSV terminé: {} succès, {} erreurs", successCount, errors.size());
        return result;
    }

    private String[] parseCSVLine(String line) {
        List<String> fields = new ArrayList<>();
        boolean inQuotes = false;
        StringBuilder currentField = new StringBuilder();

        for (int i = 0; i < line.length(); i++) {
            char c = line.charAt(i);

            if (c == '"') {
                if (inQuotes && i + 1 < line.length() && line.charAt(i + 1) == '"') {
                    // Guillemet échappé
                    currentField.append('"');
                    i++; // Passer le guillemet suivant
                } else {
                    // Toggle inQuotes
                    inQuotes = !inQuotes;
                }
            } else if (c == ',' && !inQuotes) {
                // Fin du champ
                fields.add(currentField.toString());
                currentField = new StringBuilder();
            } else {
                currentField.append(c);
            }
        }

        // Ajouter le dernier champ
        fields.add(currentField.toString());

        return fields.toArray(new String[0]);
    }

    // ==================== Méthodes privées ====================

    private void setPassword(String userId, String realmName, String password, boolean temporary) {
        try {
            UserResource userResource = keycloakAdminClient.getUsers(realmName).get(userId);

            CredentialRepresentation credential = new CredentialRepresentation();
            credential.setType(CredentialRepresentation.PASSWORD);
            credential.setValue(password);
            credential.setTemporary(temporary);

            userResource.resetPassword(credential);

            log.info("✅ Mot de passe défini pour l'utilisateur {} (temporaire: {})", userId, temporary);
        } catch (Exception e) {
            log.error("❌ Erreur lors de la définition du mot de passe pour {}", userId, e);
            throw new RuntimeException("Impossible de définir le mot de passe", e);
        }
    }

    private List<UserRepresentation> filterUsers(List<UserRepresentation> users, UserSearchCriteriaDTO criteria) {
        return users.stream()
                .filter(user -> {
                    // Filtrer par enabled
                    if (criteria.getEnabled() != null && !criteria.getEnabled().equals(user.isEnabled())) {
                        return false;
                    }

                    // Filtrer par emailVerified
                    if (criteria.getEmailVerified() != null
                            && !criteria.getEmailVerified().equals(user.isEmailVerified())) {
                        return false;
                    }

                    // Filtrer par username
                    if (criteria.getUsername() != null
                            && !criteria.getUsername().equalsIgnoreCase(user.getUsername())) {
                        return false;
                    }

                    // Filtrer par email
                    if (criteria.getEmail() != null && !criteria.getEmail().equalsIgnoreCase(user.getEmail())) {
                        return false;
                    }

                    // Filtrer par prénom
                    if (criteria.getPrenom() != null) {
                        String prenom = user.getFirstName();
                        if (prenom == null || !prenom.toLowerCase().contains(criteria.getPrenom().toLowerCase())) {
                            return false;
                        }
                    }

                    // Filtrer par nom
                    if (criteria.getNom() != null) {
                        String nom = user.getLastName();
                        if (nom == null || !nom.toLowerCase().contains(criteria.getNom().toLowerCase())) {
                            return false;
                        }
                    }

                    // Filtrer par téléphone
                    if (criteria.getTelephone() != null) {
                        String phone = user.getAttributes() != null
                                ? user.getAttributes().getOrDefault("phone_number", Collections.emptyList()).stream()
                                        .findFirst().orElse(null)
                                : null;
                        if (phone == null || !phone.contains(criteria.getTelephone())) {
                            return false;
                        }
                    }

                    // Filtrer par statut (basé sur enabled et emailVerified)
                    if (criteria.getStatut() != null) {
                        StatutUser userStatut = determineUserStatut(user);
                        if (!criteria.getStatut().equals(userStatut)) {
                            return false;
                        }
                    }

                    // Filtrer par organisation
                    if (criteria.getOrganisation() != null) {
                        String org = user.getAttributes() != null
                                ? user.getAttributes().getOrDefault("organization", Collections.emptyList()).stream()
                                        .findFirst().orElse(null)
                                : null;
                        if (org == null || !org.toLowerCase().contains(criteria.getOrganisation().toLowerCase())) {
                            return false;
                        }
                    }

                    // Filtrer par département
                    if (criteria.getDepartement() != null) {
                        String dept = user.getAttributes() != null
                                ? user.getAttributes().getOrDefault("department", Collections.emptyList()).stream()
                                        .findFirst().orElse(null)
                                : null;
                        if (dept == null || !dept.toLowerCase().contains(criteria.getDepartement().toLowerCase())) {
                            return false;
                        }
                    }

                    // Filtrer par fonction
                    if (criteria.getFonction() != null) {
                        String fonction = user.getAttributes() != null
                                ? user.getAttributes().getOrDefault("job_title", Collections.emptyList()).stream()
                                        .findFirst().orElse(null)
                                : null;
                        if (fonction == null
                                || !fonction.toLowerCase().contains(criteria.getFonction().toLowerCase())) {
                            return false;
                        }
                    }

                    // Filtrer par pays
                    if (criteria.getPays() != null) {
                        String pays = user.getAttributes() != null
                                ? user.getAttributes().getOrDefault("country", Collections.emptyList()).stream()
                                        .findFirst().orElse(null)
                                : null;
                        if (pays == null || !pays.toLowerCase().contains(criteria.getPays().toLowerCase())) {
                            return false;
                        }
                    }

                    // Filtrer par ville
                    if (criteria.getVille() != null) {
                        String ville = user.getAttributes() != null
                                ? user.getAttributes().getOrDefault("city", Collections.emptyList()).stream()
                                        .findFirst().orElse(null)
                                : null;
                        if (ville == null || !ville.toLowerCase().contains(criteria.getVille().toLowerCase())) {
                            return false;
                        }
                    }

                    // Filtrer par date de création
                    if (criteria.getDateCreationMin() != null || criteria.getDateCreationMax() != null) {
                        Long createdTimestamp = user.getCreatedTimestamp();
                        if (createdTimestamp != null) {
                            LocalDateTime createdDate = LocalDateTime.ofEpochSecond(
                                    createdTimestamp / 1000, 0,
                                    java.time.ZoneOffset.UTC);

                            if (criteria.getDateCreationMin() != null &&
                                    createdDate.isBefore(criteria.getDateCreationMin())) {
                                return false;
                            }

                            if (criteria.getDateCreationMax() != null &&
                                    createdDate.isAfter(criteria.getDateCreationMax())) {
                                return false;
                            }
                        } else {
                            // Si pas de date de création et qu'un filtre min est défini, exclure
                            if (criteria.getDateCreationMin() != null) {
                                return false;
                            }
                        }
                    }

                    return true;
                })
                .collect(Collectors.toList());
    }

    private StatutUser determineUserStatut(UserRepresentation user) {
        if (!user.isEnabled()) {
            return StatutUser.INACTIF;
        }
        // Si enabled mais email non vérifié, on considère toujours comme ACTIF
        // car l'email non vérifié n'empêche pas l'activation du compte
        return StatutUser.ACTIF;
    }
}
