package dev.lions.unionflow.server.security;

import io.quarkus.security.identity.SecurityIdentity;
import jakarta.annotation.Priority;
import jakarta.inject.Inject;
import jakarta.interceptor.AroundInvoke;
import jakarta.interceptor.Interceptor;
import jakarta.interceptor.InvocationContext;
import jakarta.persistence.EntityManager;
import lombok.extern.slf4j.Slf4j;

import java.util.UUID;

/**
 * Intercepteur CDI qui positionne les variables de session PostgreSQL pour le RLS
 * DANS la même connexion JTA que Hibernate.
 *
 * <p>Priorité 300 : s'exécute APRÈS l'intercepteur {@code @Transactional} (priorité ~200)
 * mais AVANT le code métier, garantissant que {@code SET LOCAL} affecte la connexion
 * JTA active.
 *
 * <p>Utilise {@code set_config(name, value, true)} (is_local=true) qui est l'équivalent
 * de {@code SET LOCAL} et s'annule automatiquement en fin de transaction.
 *
 * <p>Si aucun contexte d'organisation n'est disponible (SUPER_ADMIN sans org, ou endpoint
 * public), positionne l'UUID nul pour que les policies RLS utilisent le fallback.
 */
@Slf4j
@Interceptor
@RlsEnabled
@Priority(300)
public class RlsContextInterceptor {

    private static final String NULL_ORG_UUID = "00000000-0000-0000-0000-000000000000";

    @Inject
    EntityManager em;

    @Inject
    OrganisationContextHolder contextHolder;

    @Inject
    SecurityIdentity identity;

    @AroundInvoke
    Object applyRlsContext(InvocationContext ctx) throws Exception {
        if (identity == null || identity.isAnonymous()) {
            return ctx.proceed();
        }

        boolean isSuperAdmin = identity.getRoles() != null
                && (identity.getRoles().contains("SUPER_ADMIN")
                || identity.getRoles().contains("SUPERADMIN"));

        UUID orgId = contextHolder.hasContext() ? contextHolder.getOrganisationId() : null;
        String orgIdStr = orgId != null ? orgId.toString() : NULL_ORG_UUID;

        try {
            em.createNativeQuery(
                    "SELECT set_config('app.current_org_id', :orgId, true), "
                    + "set_config('app.is_super_admin', :isSuperAdmin, true)")
                    .setParameter("orgId", orgIdStr)
                    .setParameter("isSuperAdmin", String.valueOf(isSuperAdmin))
                    .getSingleResult();
            log.debug("RLS context positionné : org={}, superAdmin={}", orgIdStr, isSuperAdmin);
        } catch (Exception e) {
            // Non bloquant : en dev, le user owner bypasse naturellement les policies
            log.debug("RLS set_config ignoré (probablement hors transaction) : {}", e.getMessage());
        }

        return ctx.proceed();
    }
}
