package dev.lions.unionflow.server.service;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.enterprise.context.ApplicationScoped;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.microprofile.config.inject.ConfigProperty;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

/**
 * Client HTTP direct vers l'API Admin Keycloak (sans JAX-RS pour éviter les conflits ObjectMapper).
 * Pattern identique à KeycloakAdminClientImpl.getAllRealms() — HttpClient Java 11 + ObjectMapper isolé.
 */
@Slf4j
@ApplicationScoped
public class KeycloakAdminHttpClient {

    @ConfigProperty(name = "keycloak.admin.url", defaultValue = "http://localhost:8180")
    String keycloakUrl;

    @ConfigProperty(name = "keycloak.admin.username", defaultValue = "admin")
    String adminUsername;

    @ConfigProperty(name = "keycloak.admin.password", defaultValue = "admin")
    String adminPassword;

    @ConfigProperty(name = "keycloak.admin.realm", defaultValue = "unionflow")
    String realm;

    private final HttpClient httpClient = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10))
            .build();

    private final ObjectMapper mapper = new ObjectMapper()
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    /**
     * Obtenir un token admin depuis le realm master via client_credentials admin-cli
     */
    private String getAdminToken() throws Exception {
        String body = "client_id=admin-cli"
                + "&username=" + java.net.URLEncoder.encode(adminUsername, java.nio.charset.StandardCharsets.UTF_8)
                + "&password=" + java.net.URLEncoder.encode(adminPassword, java.nio.charset.StandardCharsets.UTF_8)
                + "&grant_type=password";

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(keycloakUrl + "/realms/master/protocol/openid-connect/token"))
                .header("Content-Type", "application/x-www-form-urlencoded")
                .POST(HttpRequest.BodyPublishers.ofString(body))
                .timeout(Duration.ofSeconds(10))
                .build();

        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() != 200) {
            throw new RuntimeException("Échec authentification admin Keycloak (HTTP " + response.statusCode() + "): " + response.body());
        }

        return mapper.readTree(response.body()).get("access_token").asText();
    }

    /**
     * Révoquer toutes les sessions actives du realm.
     * Stratégie : lister tous les users → POST /users/{id}/logout pour chaque.
     * @return nombre de sessions révoquées
     */
    public int logoutAllSessions() throws Exception {
        String token = getAdminToken();
        log.info("Token admin Keycloak obtenu — déconnexion de toutes les sessions du realm '{}'", realm);

        // Récupérer tous les utilisateurs (max 1000)
        HttpRequest usersRequest = HttpRequest.newBuilder()
                .uri(URI.create(keycloakUrl + "/admin/realms/" + realm + "/users?max=1000&enabled=true"))
                .header("Authorization", "Bearer " + token)
                .GET()
                .timeout(Duration.ofSeconds(15))
                .build();

        HttpResponse<String> usersResponse = httpClient.send(usersRequest, HttpResponse.BodyHandlers.ofString());
        if (usersResponse.statusCode() != 200) {
            throw new RuntimeException("Impossible de lister les utilisateurs Keycloak (HTTP " + usersResponse.statusCode() + ")");
        }

        var users = mapper.readTree(usersResponse.body());
        int loggedOut = 0;

        for (var user : users) {
            String userId = user.get("id").asText();
            String username = user.has("username") ? user.get("username").asText() : userId;

            HttpRequest logoutRequest = HttpRequest.newBuilder()
                    .uri(URI.create(keycloakUrl + "/admin/realms/" + realm + "/users/" + userId + "/logout"))
                    .header("Authorization", "Bearer " + token)
                    .POST(HttpRequest.BodyPublishers.noBody())
                    .timeout(Duration.ofSeconds(5))
                    .build();

            HttpResponse<String> logoutResponse = httpClient.send(logoutRequest, HttpResponse.BodyHandlers.ofString());
            if (logoutResponse.statusCode() == 204 || logoutResponse.statusCode() == 200) {
                loggedOut++;
                log.debug("Session révoquée pour l'utilisateur '{}'", username);
            } else {
                log.warn("Impossible de révoquer la session de '{}' (HTTP {})", username, logoutResponse.statusCode());
            }
        }

        log.info("Déconnexion globale terminée: {}/{} utilisateur(s) déconnecté(s)", loggedOut, users.size());
        return loggedOut;
    }
}
