#![allow(dead_code)]
#![allow(unused_imports)]
use crate::auth::jwt::Claims;
use crate::config::AppState;
use axum::{
    extract::{Request, State},
    http::StatusCode,
    middleware::Next,
    response::Response,
};
use mongodb::bson::oid::ObjectId;

pub async fn jwt_auth_middleware(
    State(state): State<AppState>,
    mut req: Request,
    next: Next,
) -> Result<Response, StatusCode> {
    let headers = req.headers();

    // Extract Authorization header
    let auth_header = headers
        .get("Authorization")
        .and_then(|h| h.to_str().ok())
        .ok_or(StatusCode::UNAUTHORIZED)?;

    // Check Bearer token format
    if !auth_header.starts_with("Bearer ") {
        return Err(StatusCode::UNAUTHORIZED);
    }

    let token = &auth_header[7..]; // Remove "Bearer " prefix

    // Verify signature and expiry.
    let claims = state
        .jwt_service
        .validate_token(token)
        .map_err(|_| StatusCode::UNAUTHORIZED)?;

    // Reject tokens whose version is stale (e.g. issued before a password
    // change). The user's current version is cached briefly so we don't hit
    // Mongo on every request; a missing user (deleted) also means 401.
    let user_oid = ObjectId::parse_str(&claims.sub).map_err(|_| StatusCode::UNAUTHORIZED)?;
    let current_version = state
        .token_version_cache
        .get_or_load(&user_oid, &state.db)
        .await
        .map_err(|_| StatusCode::UNAUTHORIZED)?;
    match current_version {
        Some(v) if v == claims.token_version => {}
        _ => return Err(StatusCode::UNAUTHORIZED),
    }

    // Add claims to request extensions for handlers to use
    req.extensions_mut().insert(claims);

    Ok(next.run(req).await)
}

// Extension method to extract claims from request
pub trait RequestClaimsExt {
    fn claims(&self) -> Option<&Claims>;
}

impl RequestClaimsExt for Request {
    fn claims(&self) -> Option<&Claims> {
        self.extensions().get::<Claims>()
    }
}
