//! RBAC Middleware for Axum
//!
//! Provides middleware to enforce RBAC on API endpoints

use super::{RbacManager, Resource, Action, User, RbacError};
use axum::{
    extract::{Request, State},
    http::StatusCode,
    middleware::Next,
    response::{IntoResponse, Response},
    Json,
};
use serde_json::json;
use std::sync::Arc;

/// RBAC middleware state
#[derive(Clone)]
pub struct RbacMiddleware {
    rbac_manager: Arc<RbacManager>,
}

impl RbacMiddleware {
    pub fn new(rbac_manager: Arc<RbacManager>) -> Self {
        Self { rbac_manager }
    }

    /// Check permission middleware
    pub async fn check_permission(
        State(state): State<Arc<Self>>,
        resource: Resource,
        action: Action,
        mut req: Request,
        next: Next,
    ) -> Result<Response, RbacError> {
        // Extract user from request extensions (set by auth middleware)
        let user = req.extensions()
            .get::<User>()
            .ok_or(RbacError::UserNotFound("No user in request".to_string()))?
            .clone();

        // Check permission
        if !state.rbac_manager.check_permission(&user, resource, action).await {
            return Err(RbacError::PermissionDenied);
        }

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

/// Convert RBAC error to HTTP response
impl IntoResponse for RbacError {
    fn into_response(self) -> Response {
        let (status, message) = match self {
            RbacError::PermissionDenied => (
                StatusCode::FORBIDDEN,
                "Permission denied".to_string(),
            ),
            RbacError::UserNotFound(msg) => (
                StatusCode::UNAUTHORIZED,
                format!("User not found: {}", msg),
            ),
            RbacError::ModeSwitchDisabled => (
                StatusCode::FORBIDDEN,
                "Mode switching is disabled".to_string(),
            ),
            RbacError::RoleAssignmentNotAllowed => (
                StatusCode::FORBIDDEN,
                "Role assignment not allowed in current mode".to_string(),
            ),
            RbacError::InvalidRole => (
                StatusCode::BAD_REQUEST,
                "Invalid role".to_string(),
            ),
        };

        let body = Json(json!({
            "error": message,
            "status": status.as_u16(),
        }));

        (status, body).into_response()
    }
}

/// Helper macro to create RBAC middleware for specific resource/action
#[macro_export]
macro_rules! rbac_middleware {
    ($resource:expr, $action:expr) => {
        |state, req, next| async move {
            RbacMiddleware::check_permission(state, $resource, $action, req, next).await
        }
    };
}

#[cfg(test)]
mod tests {
    use super::*;

    // Tests would use axum test helpers
}
