package dev.lions.unionflow.client.security;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jboss.logging.Logger;

import java.io.IOException;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * Filtre pour générer et injecter des nonces CSP (Content Security Policy).
 * 
 * <p>Ce filtre génère un nonce unique pour chaque requête et l'ajoute:
 * <ul>
 *   <li>Comme attribut de requête pour utilisation dans les templates JSF</li>
 *   <li>Dans l'en-tête CSP pour autoriser les scripts/styles inline</li>
 * </ul>
 * 
 * <p>Utilisation dans les templates:
 * <pre>
 * &lt;script nonce="#{request.getAttribute('csp-nonce')}"&gt;
 *   // Code JavaScript
 * &lt;/script&gt;
 * </pre>
 *
 * @author UnionFlow Team
 * @version 1.0
 */
public class CSPNonceFilter implements Filter {

    private static final Logger LOG = Logger.getLogger(CSPNonceFilter.class);
    private static final SecureRandom SECURE_RANDOM = new SecureRandom();
    private static final int NONCE_LENGTH = 16;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOG.info("Initialisation du filtre CSP Nonce");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        
        if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            HttpServletResponse httpResponse = (HttpServletResponse) response;

            // Générer un nonce unique pour cette requête
            String nonce = generateNonce();
            
            // Ajouter le nonce comme attribut de requête pour utilisation dans les templates
            httpRequest.setAttribute("csp-nonce", nonce);
            
            // Construire la politique CSP avec le nonce
            String cspPolicy = buildCSPPolicy(nonce);
            
            // Ajouter l'en-tête CSP
            httpResponse.setHeader("Content-Security-Policy", cspPolicy);
            
            LOG.debugf("Nonce CSP généré et injecté: %s", nonce.substring(0, 8) + "...");
        }

        chain.doFilter(request, response);
    }

    /**
     * Génère un nonce aléatoire sécurisé.
     * 
     * @return Nonce encodé en Base64
     */
    private String generateNonce() {
        byte[] nonceBytes = new byte[NONCE_LENGTH];
        SECURE_RANDOM.nextBytes(nonceBytes);
        return Base64.getEncoder().encodeToString(nonceBytes);
    }

    /**
     * Construit la politique CSP avec le nonce.
     * 
     * @param nonce Le nonce à inclure dans la politique
     * @return Politique CSP complète
     */
    private String buildCSPPolicy(String nonce) {
        // Politique CSP stricte avec nonces pour scripts et styles inline
        return String.format(
            "default-src 'self'; " +
            "script-src 'self' 'nonce-%s' 'strict-dynamic' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com; " +
            "style-src 'self' 'nonce-%s' 'unsafe-inline' https://fonts.googleapis.com; " +
            "font-src 'self' https://fonts.gstatic.com data:; " +
            "img-src 'self' data: https:; " +
            "connect-src 'self' %s; " +
            "frame-ancestors 'none'; " +
            "base-uri 'self'; " +
            "form-action 'self'; " +
            "upgrade-insecure-requests;",
            nonce, nonce, getBackendUrl()
        );
    }

    /**
     * Récupère l'URL du backend depuis la configuration.
     * 
     * @return URL du backend ou 'self' par défaut
     */
    private String getBackendUrl() {
        // Récupérer depuis la configuration Quarkus
        String backendUrl = System.getProperty("unionflow.backend.url", 
                                               System.getenv("UNIONFLOW_BACKEND_URL"));
        if (backendUrl != null && !backendUrl.isEmpty()) {
            return backendUrl;
        }
        return "'self'";
    }

    @Override
    public void destroy() {
        LOG.info("Destruction du filtre CSP Nonce");
    }
}

