use axum::{
    extract::FromRequestParts,
    http::{request::Parts, StatusCode},
};
use std::future::Future;

pub struct RequireAuth(pub crate::jwt::Claims);

impl<S> FromRequestParts<S> for RequireAuth
where
    S: Send + Sync,
{
    type Rejection = (StatusCode, &'static str);

    fn from_request_parts(
        parts: &mut Parts,
        _state: &S,
    ) -> impl Future<Output = Result<Self, Self::Rejection>> + Send {
        let token = parts
            .headers
            .get("Authorization")
            .and_then(|value| value.to_str().ok())
            .filter(|value| value.starts_with("Bearer "))
            .map(|header| header.trim_start_matches("Bearer ").to_string());

        async move {
            let token = match token {
                Some(token) => token,
                None => return Err((StatusCode::UNAUTHORIZED, "Missing Bearer token")),
            };

            let jwt_secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set");

            match crate::jwt::verify_access_token(&token, &jwt_secret) {
                Ok(claims) => Ok(RequireAuth(claims)),
                Err(_) => Err((StatusCode::UNAUTHORIZED, "Invalid or expired token")),
            }
        }
    }
}
