//! Bearer token extractor for Axum
//!
//! Extracts JWT tokens from the Authorization header in the format:
//! `Authorization: Bearer <token>`

use std::pin::Pin;
use std::future::Future;
use axum::{
    extract::FromRequestParts,
    http::request::Parts,
};
use shared_api_lib::error::ApiError;

/// Bearer token extracted from Authorization header
///
/// Extracts and validates the Authorization header format.
/// Does NOT validate the JWT signature - that's done by the AuthUser extractor.
#[derive(Debug, Clone)]
pub struct BearerToken(pub String);

impl<S> FromRequestParts<S> for BearerToken
where
    S: Send + Sync,
{
    type Rejection = ApiError;

    fn from_request_parts<'a>(
        parts: &'a mut Parts,
        _state: &'a S,
    ) -> Pin<Box<dyn Future<Output = Result<Self, Self::Rejection>> + Send + 'a>> {
        Box::pin(async move {
            let auth_header = parts
                .headers
                .get("Authorization")
                .and_then(|h| h.to_str().ok())
                .ok_or_else(|| {
                    ApiError::Unauthorized("Missing Authorization header".to_string())
                })?;

            if !auth_header.starts_with("Bearer ") {
                return Err(ApiError::Unauthorized(
                    "Invalid Authorization header format. Expected: Bearer <token>".to_string(),
                ));
            }

            let token = auth_header
                .strip_prefix("Bearer ")
                .map(|s| s.to_string())
                .ok_or_else(|| {
                    ApiError::Unauthorized("Empty token in Authorization header".to_string())
                })?;

            if token.is_empty() {
                return Err(ApiError::Unauthorized(
                    "Empty token in Authorization header".to_string(),
                ));
            }

            Ok(BearerToken(token))
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use axum::http::{HeaderMap, HeaderValue, Request};
    use hyper::Body;

    #[tokio::test]
    async fn test_bearer_token_extraction() {
        let mut headers = HeaderMap::new();
        headers.insert(
            "Authorization",
            HeaderValue::from_static("Bearer my_test_token_123"),
        );

        let mut parts = Request::<Body>::builder()
            .header("Authorization", "Bearer my_test_token_123")
            .body(Body::empty())
            .unwrap()
            .into_parts()
            .0;

        // Create a minimal Parts struct for testing
        // In real usage, this is extracted by Axum automatically
        let token_str = "my_test_token_123";
        let bearer = BearerToken(token_str.to_string());
        assert_eq!(bearer.0, token_str);
    }

    #[test]
    fn test_bearer_token_format() {
        let token = BearerToken("test_token_123".to_string());
        assert_eq!(token.0, "test_token_123");
    }
}
