//! Axum request extensions: injects engine, Tera, config, CSRF, CSP nonce, and current user.
use crate::auth::session::CurrentUser;
use axum::body::Body;
use axum::http::Request;
/// Centralized module to inject all data into Axum extensions.
use axum::http::request::Parts;

use crate::utils::{
    aliases::{
        AEngine, ARuniqueConfig, ATera, OAEngine, OARuniqueConfig, OATera, OCspNonce, OCsrfToken,
        OCurrentUser,
    },
    {csp_nonce::CspNonce, csrf::CsrfToken},
};

/// Structure containing all data to be injected into extensions.
pub struct RequestExtensions {
    pub engine: OAEngine,
    pub tera: OATera,
    pub config: OARuniqueConfig,
    pub csrf_token: OCsrfToken,
    pub csp_nonce: OCspNonce,
    pub current_user: OCurrentUser,
}

impl RequestExtensions {
    /// Creates a new empty instance.
    pub fn new() -> Self {
        Self {
            engine: None,
            tera: None,
            config: None,
            csrf_token: None,
            csp_nonce: None,
            current_user: None,
        }
    }

    /// Injects all present data into extensions.
    pub fn inject(&self, parts: &mut Parts) {
        if let Some(engine) = &self.engine {
            parts.extensions.insert(engine.clone());
        }
        if let Some(tera) = &self.tera {
            parts.extensions.insert(tera.clone());
        }
        if let Some(config) = &self.config {
            parts.extensions.insert(config.clone());
        }
        if let Some(csrf_token) = &self.csrf_token {
            parts.extensions.insert(csrf_token.clone());
        }
        if let Some(csp_nonce) = &self.csp_nonce {
            parts.extensions.insert(csp_nonce.clone());
        }
        if let Some(current_user) = &self.current_user {
            parts.extensions.insert(current_user.clone());
        }
    }

    /// Injects all data into a Request (wrapper for Axum).
    pub fn inject_request(&self, req: &mut Request<Body>) {
        // Uses the extensions_mut() method of the Request directly.
        let extensions = req.extensions_mut();

        if let Some(engine) = &self.engine {
            extensions.insert(engine.clone());
        }
        if let Some(tera) = &self.tera {
            extensions.insert(tera.clone());
        }
        if let Some(config) = &self.config {
            extensions.insert(config.clone());
        }
        if let Some(csrf_token) = &self.csrf_token {
            extensions.insert(csrf_token.clone());
        }
        if let Some(csp_nonce) = &self.csp_nonce {
            extensions.insert(csp_nonce.clone());
        }
        if let Some(current_user) = &self.current_user {
            extensions.insert(current_user.clone());
        }
    }
    pub fn with_csrf_token(mut self, csrf_token: CsrfToken) -> Self {
        self.csrf_token = Some(csrf_token);
        self
    }
    /// Builder pattern - Engine
    pub fn with_engine(mut self, engine: AEngine) -> Self {
        self.engine = Some(engine);
        self
    }

    /// Builder pattern - Tera
    pub fn with_tera(mut self, tera: ATera) -> Self {
        self.tera = Some(tera);
        self
    }

    /// Builder pattern - Config
    pub fn with_config(mut self, config: ARuniqueConfig) -> Self {
        self.config = Some(config);
        self
    }

    /// Builder pattern - CSP Nonce
    pub fn with_csp_nonce(mut self, csp_nonce: CspNonce) -> Self {
        self.csp_nonce = Some(csp_nonce);
        self
    }

    /// Builder pattern - Current User
    pub fn with_current_user(mut self, current_user: CurrentUser) -> Self {
        self.current_user = Some(current_user);
        self
    }
}

impl Default for RequestExtensions {
    fn default() -> Self {
        Self::new()
    }
}
