package dev.lions.unionflow.server.security;

import io.quarkus.security.identity.SecurityIdentity;
import jakarta.annotation.Priority;
import jakarta.inject.Inject;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.ext.Provider;
import lombok.extern.slf4j.Slf4j;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.UUID;

/**
 * Filtre JAX-RS qui positionne les variables de session PostgreSQL pour le RLS.
 *
 * <p>Doit s'exécuter APRÈS {@link OrganisationContextFilter} (priorité AUTHORIZATION + 20).
 *
 * <p>Variables positionnées :
 * <ul>
 *   <li>{@code app.current_org_id} : UUID de l'organisation active (null → "00000000-0000-0000-0000-000000000000")</li>
 *   <li>{@code app.is_super_admin} : 'true' si SUPER_ADMIN (bypass RLS pour requêtes cross-tenant)</li>
 * </ul>
 *
 * <p><strong>Limitation connue</strong> : ce filtre ouvre une connexion séparée du pool Agroal.
 * {@code SET LOCAL} affecte CETTE connexion, pas celle utilisée par Hibernate pour les queries.
 * Pour une isolation réelle, il faut brancher le {@code SET} sur le même contexte transactionnel
 * Hibernate — via {@code CurrentTenantIdentifierResolver} + {@code MultiTenantConnectionProvider},
 * ou via un {@code TransactionSynchronization} qui s'exécute dans la même transaction JTA.
 * Ce filtre est un draft de préparation prod ; l'intégration complète est prévue en P2.4.
 *
 * <p>En dev, RLS est désactivé de fait car le user {@code skyfile} est owner
 * et bypasse naturellement les policies. Ce filter est actif pour la préparation prod.
 */
@Slf4j
@Provider
@Priority(Priorities.AUTHORIZATION + 20)
public class RlsConnectionInitializer implements ContainerRequestFilter {

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

    @Inject
    OrganisationContextHolder contextHolder;

    @Inject
    SecurityIdentity identity;

    @Inject
    DataSource dataSource;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        if (identity == null || identity.isAnonymous()) return;

        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_ID;

        try (Connection conn = dataSource.getConnection()) {
            try (PreparedStatement stmt = conn.prepareStatement(
                    "SET LOCAL app.current_org_id = '" + orgIdStr + "'; "
                    + "SET LOCAL app.is_super_admin = '" + isSuperAdmin + "'")) {
                stmt.execute();
            }
        } catch (Exception e) {
            // Non bloquant en dev (user owner bypasse RLS)
            log.debug("RLS session variables non positionnées (ignoré en dev) : {}", e.getMessage());
        }
    }
}
