package dev.lions.unionflow.server.client;

import io.quarkus.oidc.runtime.OidcJwtCallerPrincipal;
import io.quarkus.security.identity.SecurityIdentity;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.client.ClientRequestContext;
import jakarta.ws.rs.client.ClientRequestFilter;
import jakarta.ws.rs.core.HttpHeaders;
import org.eclipse.microprofile.jwt.JsonWebToken;
import org.jboss.logging.Logger;

import java.io.IOException;

/**
 * Filtre REST Client qui propage le token JWT de la requête entrante.
 *
 * <p>NE PAS annoter avec {@code @Provider} — cela l'enregistrerait GLOBALEMENT
 * sur tous les REST clients, y compris AdminUserServiceClient/AdminRoleServiceClient
 * qui utilisent AdminServiceTokenHeadersFactory (service account). Le filtre global
 * écraserait le token de service account avec le JWT utilisateur → 401 sur LUM.
 *
 * <p>{@code @ApplicationScoped} est requis pour la découverte CDI (tests {@code @QuarkusTest}
 * qui {@code @Inject} le filter). Cela ne provoque PAS d'enregistrement automatique JAX-RS
 * — l'opt-in se fait via {@code @RegisterProvider(JwtPropagationFilter.class)} sur les
 * REST clients qui le souhaitent.
 *
 * <p>La propagation JWT par défaut est assurée par {@link OidcTokenPropagationHeadersFactory}
 * sur les clients qui en ont besoin ({@code @RegisterClientHeaders}).
 */
@ApplicationScoped
public class JwtPropagationFilter implements ClientRequestFilter {

    private static final Logger LOG = Logger.getLogger(JwtPropagationFilter.class);

    @Inject
    SecurityIdentity securityIdentity;

    @Override
    public void filter(ClientRequestContext requestContext) throws IOException {
        if (securityIdentity != null && !securityIdentity.isAnonymous()) {
            // Récupérer le token JWT depuis le principal
            if (securityIdentity.getPrincipal() instanceof OidcJwtCallerPrincipal) {
                OidcJwtCallerPrincipal principal = (OidcJwtCallerPrincipal) securityIdentity.getPrincipal();
                String token = principal.getRawToken();

                if (token != null && !token.isBlank()) {
                    requestContext.getHeaders().putSingle(
                        HttpHeaders.AUTHORIZATION,
                        "Bearer " + token
                    );
                    LOG.debugf("Token JWT propagé vers %s", requestContext.getUri());
                } else {
                    LOG.warnf("Token JWT vide pour %s", requestContext.getUri());
                }
            } else if (securityIdentity.getPrincipal() instanceof JsonWebToken) {
                JsonWebToken jwt = (JsonWebToken) securityIdentity.getPrincipal();
                String token = jwt.getRawToken();

                if (token != null && !token.isBlank()) {
                    requestContext.getHeaders().putSingle(
                        HttpHeaders.AUTHORIZATION,
                        "Bearer " + token
                    );
                    LOG.debugf("Token JWT propagé vers %s", requestContext.getUri());
                }
            } else {
                LOG.warnf("Principal n'est pas un JWT pour %s (type: %s)",
                    requestContext.getUri(),
                    securityIdentity.getPrincipal().getClass().getName());
            }
        } else {
            LOG.warnf("Pas de SecurityIdentity ou utilisateur anonyme pour %s",
                requestContext.getUri());
        }
    }
}
