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

import dev.lions.user.manager.client.KeycloakAdminClient;
import dev.lions.user.manager.dto.role.RoleDTO;
import dev.lions.user.manager.dto.sync.HealthStatusDTO;
import dev.lions.user.manager.dto.sync.SyncResultDTO;
import dev.lions.user.manager.dto.user.UserDTO;
import dev.lions.user.manager.enums.role.TypeRole;
import dev.lions.user.manager.mapper.RoleMapper;
import dev.lions.user.manager.mapper.UserMapper;
import dev.lions.user.manager.service.SyncService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.validation.constraints.NotBlank;
import lombok.extern.slf4j.Slf4j;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Implémentation du service de synchronisation avec Keycloak
 *
 * Ce service permet de:
 * - Synchroniser les utilisateurs depuis Keycloak
 * - Synchroniser les rôles depuis Keycloak
 * - Vérifier la cohérence des données
 * - Effectuer des health checks sur Keycloak
 */
@ApplicationScoped
@Slf4j
public class SyncServiceImpl implements SyncService {

    @Inject
    KeycloakAdminClient keycloakAdminClient;

    @Override
    public int syncUsersFromRealm(@NotBlank String realmName) {
        log.info("Synchronisation des utilisateurs depuis le realm: {}", realmName);

        try {
            List<UserRepresentation> userReps = keycloakAdminClient.getInstance()
                .realm(realmName)
                .users()
                .list();

            int count = userReps.size();
            log.info("✅ {} utilisateurs synchronisés depuis le realm {}", count, realmName);
            return count;
        } catch (Exception e) {
            log.error("❌ Erreur lors de la synchronisation des utilisateurs depuis le realm {}", realmName, e);
            throw new RuntimeException("Erreur lors de la synchronisation des utilisateurs", e);
        }
    }

    @Override
    public int syncRolesFromRealm(@NotBlank String realmName) {
        log.info("Synchronisation des rôles depuis le realm: {}", realmName);

        try {
            List<RoleRepresentation> roleReps = keycloakAdminClient.getInstance()
                .realm(realmName)
                .roles()
                .list();

            int count = roleReps.size();
            log.info("✅ {} rôles synchronisés depuis le realm {}", count, realmName);
            return count;
        } catch (Exception e) {
            log.error("❌ Erreur lors de la synchronisation des rôles depuis le realm {}", realmName, e);
            throw new RuntimeException("Erreur lors de la synchronisation des rôles", e);
        }
    }

    @Override
    public Map<String, Integer> syncAllRealms() {
        log.info("Synchronisation de tous les realms");

        Map<String, Integer> results = new java.util.HashMap<>();
        
        try {
            // Lister tous les realms
            List<org.keycloak.representations.idm.RealmRepresentation> realms = 
                keycloakAdminClient.getInstance().realms().findAll();
            
            for (org.keycloak.representations.idm.RealmRepresentation realm : realms) {
                String realmName = realm.getRealm();
                try {
                    int usersCount = syncUsersFromRealm(realmName);
                    int rolesCount = syncRolesFromRealm(realmName);
                    results.put(realmName, usersCount + rolesCount);
                } catch (Exception e) {
                    log.error("Erreur lors de la synchronisation du realm {}", realmName, e);
                    results.put(realmName, 0);
                }
            }
        } catch (Exception e) {
            log.error("Erreur lors de la synchronisation de tous les realms", e);
        }

        return results;
    }

    @Override
    public Map<String, Object> checkDataConsistency(@NotBlank String realmName) {
        log.info("Vérification de la cohérence des données pour le realm: {}", realmName);

        Map<String, Object> report = new java.util.HashMap<>();
        
        try {
            // Pour l'instant, on retourne juste un rapport basique
            // En production, on comparerait avec un cache local
            report.put("realmName", realmName);
            report.put("status", "ok");
            report.put("message", "Cohérence vérifiée");
        } catch (Exception e) {
            log.error("Erreur lors de la vérification de cohérence pour le realm {}", realmName, e);
            report.put("status", "error");
            report.put("message", e.getMessage());
        }

        return report;
    }

    @Override
    public Map<String, Object> forceSyncRealm(@NotBlank String realmName) {
        log.info("Synchronisation forcée du realm: {}", realmName);

        Map<String, Object> stats = new java.util.HashMap<>();
        long startTime = System.currentTimeMillis();

        try {
            int usersCount = syncUsersFromRealm(realmName);
            int rolesCount = syncRolesFromRealm(realmName);
            
            stats.put("realmName", realmName);
            stats.put("usersCount", usersCount);
            stats.put("rolesCount", rolesCount);
            stats.put("success", true);
            stats.put("durationMs", System.currentTimeMillis() - startTime);
        } catch (Exception e) {
            log.error("Erreur lors de la synchronisation forcée du realm {}", realmName, e);
            stats.put("success", false);
            stats.put("error", e.getMessage());
            stats.put("durationMs", System.currentTimeMillis() - startTime);
        }

        return stats;
    }

    @Override
    public Map<String, Object> getLastSyncStatus(@NotBlank String realmName) {
        log.debug("Récupération du statut de la dernière synchronisation pour le realm: {}", realmName);

        Map<String, Object> status = new java.util.HashMap<>();
        status.put("realmName", realmName);
        status.put("lastSyncTime", System.currentTimeMillis()); // En production, récupérer depuis un cache
        status.put("status", "completed");
        
        return status;
    }

    @Override
    public boolean isKeycloakAvailable() {
        log.debug("Vérification de la disponibilité de Keycloak");

        try {
            // Test de connexion en récupérant les informations du serveur
            keycloakAdminClient.getInstance().serverInfo().getInfo();
            log.debug("✅ Keycloak est accessible et fonctionne");
            return true;
        } catch (Exception e) {
            log.error("❌ Keycloak n'est pas accessible: {}", e.getMessage());
            return false;
        }
    }

    @Override
    public Map<String, Object> getKeycloakHealthInfo() {
        log.info("Récupération du statut de santé complet de Keycloak");

        Map<String, Object> healthInfo = new java.util.HashMap<>();
        healthInfo.put("timestamp", System.currentTimeMillis());

        try {
            // Test connexion principale
            var serverInfo = keycloakAdminClient.getInstance().serverInfo().getInfo();
            healthInfo.put("keycloakAccessible", true);
            healthInfo.put("keycloakVersion", serverInfo.getSystemInfo().getVersion());

            // Test des realms (on essaie juste de lister)
            try {
                int realmsCount = keycloakAdminClient.getInstance().realms().findAll().size();
                healthInfo.put("realmsAccessible", true);
                healthInfo.put("realmsCount", realmsCount);
            } catch (Exception e) {
                healthInfo.put("realmsAccessible", false);
                log.warn("Impossible d'accéder aux realms: {}", e.getMessage());
            }

            healthInfo.put("overallHealthy", true);
            log.info("✅ Keycloak est en bonne santé - Version: {}, Realms: {}",
                     healthInfo.get("keycloakVersion"), healthInfo.get("realmsCount"));

        } catch (Exception e) {
            healthInfo.put("keycloakAccessible", false);
            healthInfo.put("overallHealthy", false);
            healthInfo.put("errorMessage", e.getMessage());
            log.error("❌ Keycloak n'est pas accessible: {}", e.getMessage());
        }

        return healthInfo;
    }
}
