package fr.titionfire.ffsaf.domain.service;

import fr.titionfire.ffsaf.rest.client.HelloAssoAuthClient;
import fr.titionfire.ffsaf.rest.client.dto.TokenResponse;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.jboss.logging.Logger;

@ApplicationScoped
public class HelloAssoTokenService {
    private static final Logger LOG = Logger.getLogger(HelloAssoTokenService.class);

    @RestClient
    HelloAssoAuthClient authClient;

    @ConfigProperty(name = "helloasso.client-id")
    String clientId;

    @ConfigProperty(name = "helloasso.client-secret")
    String clientSecret;

    private TokenResponse currentToken; // Stockage en mémoire (pour un seul pod)

    // Récupère un token valide (en le rafraîchissant si nécessaire)
    public Uni<String> getValidAccessToken() {
        if (clientId == null || clientSecret == null || clientId.isEmpty() || clientSecret.isEmpty() || clientId.equalsIgnoreCase(
                "null") || clientSecret.equalsIgnoreCase("null")) {
            LOG.error("Client ID ou Client Secret non configuré pour HelloAsso");
            return Uni.createFrom().failure(new IllegalStateException("HelloAsso client credentials not configured"));
        }
        if (currentToken == null || currentToken.isExpired()) {
            return fetchNewToken(clientId, clientSecret);
        }
        return Uni.createFrom().item(currentToken.accessToken);
    }

    // Récupère un nouveau token (via client_credentials ou refresh_token)
    private Uni<String> fetchNewToken(String clientId, String clientSecret) {
        if (currentToken != null && currentToken.refreshToken != null) {
            // On utilise le refresh_token si disponible
            return authClient.refreshToken("refresh_token", clientId, currentToken.refreshToken)
                    .onItem().invoke(token -> {
                        LOG.info("Token rafraîchi avec succès");
                        currentToken = token;
                    })
                    .onFailure().recoverWithItem(e -> {
                        LOG.warn("Échec du rafraîchissement, utilisation des credentials", e);
                        return null; // Force l'utilisation des credentials
                    })
                    .flatMap(token -> token != null ?
                            Uni.createFrom().item(token.accessToken) :
                            getTokenWithCredentials(clientId, clientSecret)
                    );
        } else {
            return getTokenWithCredentials(clientId, clientSecret);
        }
    }

    // Récupère un token avec client_id/client_secret
    private Uni<String> getTokenWithCredentials(String clientId, String clientSecret) {
        return authClient.getToken("client_credentials", clientId, clientSecret)
                .onItem().invoke(token -> {
                    LOG.info("Nouveau token obtenu");
                    currentToken = token;
                })
                .onFailure().invoke(e -> LOG.error("Erreur lors de l'obtention du token", e))
                .map(token -> token.accessToken);
    }
}
