//! Auth middleware — extracts and verifies auth tokens from requests.
//!
//! In an axum application:
//! ```text
//! let app = Router::new()
//!     .route("/api/users", get(list_users))
//!     .layer(AuthMiddleware::new(jwt_provider));
//! ```
//!
//! The middleware populates `AuthContext` from the `Authorization` header.

use crate::{AuthContext, AuthProvider, AuthResult};
use std::sync::Arc;

/// Auth middleware — wraps an auth provider to extract context from HTTP headers.
pub struct AuthMiddleware {
    provider: Arc<dyn AuthProvider>,
}

impl AuthMiddleware {
    pub fn new(provider: Arc<dyn AuthProvider>) -> Self {
        Self { provider }
    }

    /// Extract and verify the auth token from an Authorization header value.
    ///
    /// Supported formats:
    /// - `Bearer <token>` — JWT or opaque token
    /// - `Session <session_id>` — server-side session
    pub fn authenticate_from_header(&self, authorization: Option<&str>) -> AuthResult<AuthContext> {
        match authorization {
            None => Ok(AuthContext::anonymous()),
            Some(header) => {
                let token = if let Some(t) = header.strip_prefix("Bearer ") {
                    t.trim()
                } else if let Some(t) = header.strip_prefix("Session ") {
                    t.trim()
                } else {
                    header.trim()
                };
                self.provider.verify(token)
            }
        }
    }

    /// Authenticate from a query parameter (for WebSocket upgrades where
    /// Authorization headers can't be set from JS).
    pub fn authenticate_from_query_param(&self, token: Option<&str>) -> AuthResult<AuthContext> {
        match token {
            None => Ok(AuthContext::anonymous()),
            Some(t) => self.provider.verify(t),
        }
    }

    /// Get the underlying provider name.
    pub fn provider_name(&self) -> &'static str {
        self.provider.name()
    }
}
