use athena_auth_core::adapters::DatabaseAdapter;
use athena_auth_core::entity::{AuthApiKey, AuthSession, AuthUser};
use athena_auth_core::error::request_trace_id_from_auth_request;
use athena_auth_core::{AuthContext, AuthError, AuthResult, merge_email_metadata};
use athena_auth_core::{
    AuthPlugin, AuthRequest, AuthResponse, AuthRoute, CreateAdminAuditLog, HttpMethod,
};
use base64::Engine;
use sha2::{Digest, Sha256};

use crate::plugins::api_key_shared::stored_api_key_grant_keys;
use crate::plugins::grants::native_right_keys_for_grant_keys;
use athena_auth_core::utils::cookie_utils::{create_clear_session_cookie, create_session_cookie};

pub(super) mod handlers;
pub(super) mod types;

#[cfg(test)]
mod tests;

use handlers::*;
use types::*;

// ---------------------------------------------------------------------------
// Plugin & config
// ---------------------------------------------------------------------------

/// Admin plugin for user management operations.
///
/// Provides endpoints for creating users, listing users, banning/unbanning,
/// role management, session management, password management, user impersonation,
/// and permission checks.
///
/// All endpoints require an authenticated session with the `admin` role.
#[derive(Clone)]
pub struct AdminPlugin {
    config: AdminConfig,
}

/// Configuration for the admin plugin.
#[derive(Debug, Clone, athena_auth_core::PluginConfig)]
#[plugin(name = "AdminPlugin")]
pub struct AdminConfig {
    /// The role required to access admin endpoints (default: `"admin"`).
    #[config(default = "admin".to_string())]
    pub admin_role: String,
    /// Default role assigned to newly created users (default: `"user"`).
    #[config(default = "user".to_string())]
    pub default_user_role: String,
    /// Whether to allow banning other admins (default: `false`).
    #[config(default = false)]
    pub allow_ban_admin: bool,
    /// Default number of users returned in list-users (default: 100).
    #[config(default = 100)]
    pub default_page_limit: usize,
    /// Maximum number of users returned in list-users (default: 500).
    #[config(default = 500)]
    pub max_page_limit: usize,
    /// Optional grant catalog used to resolve native grant keys and subject grants.
    #[config(default = Vec::new(), skip)]
    pub grant_catalog: Vec<athena_auth_core::GrantDescriptor>,
    /// Rich native-right metadata exposed through the admin catalog route.
    #[config(default = Vec::new(), skip)]
    pub native_right_catalog: Vec<athena_rights::AthenaRightDescriptor>,
    /// Optional module-scoped integration contracts keyed by native-right source.
    #[config(default = std::collections::BTreeMap::new(), skip)]
    pub native_right_domain_contracts: std::collections::BTreeMap<String, serde_json::Value>,
}

impl AdminConfig {
    pub fn effective_grant_catalog(&self) -> Vec<athena_auth_core::GrantDescriptor> {
        crate::plugins::grants::merged_grant_catalog(
            &self.grant_catalog,
            &self.native_right_catalog,
        )
    }

    pub fn merged_native_right_catalog(&self) -> Vec<athena_rights::AthenaRightDescriptor> {
        crate::plugins::grants::merged_native_right_catalog(&self.native_right_catalog)
    }

    pub fn native_right_domain_integration_contract(
        &self,
        module_key: &str,
    ) -> Option<serde_json::Value> {
        self.native_right_domain_contracts.get(module_key).cloned()
    }
}

// ---------------------------------------------------------------------------
// Plugin trait implementation
// ---------------------------------------------------------------------------

const ADMIN_ROUTES: &[(HttpMethod, &str, &str, &str)] = &[
    (
        HttpMethod::Post,
        "/admin/set-role",
        "admin_set_role",
        "admin.set_role",
    ),
    (
        HttpMethod::Post,
        "/admin/create-user",
        "admin_create_user",
        "admin.create_user",
    ),
    (
        HttpMethod::Get,
        "/admin/list-users",
        "admin_list_users",
        "admin.list_users",
    ),
    (
        HttpMethod::Post,
        "/admin/list-user-sessions",
        "admin_list_user_sessions",
        "admin.list_user_sessions",
    ),
    (
        HttpMethod::Post,
        "/admin/ban-user",
        "admin_ban_user",
        "admin.ban_user",
    ),
    (
        HttpMethod::Post,
        "/admin/unban-user",
        "admin_unban_user",
        "admin.unban_user",
    ),
    (
        HttpMethod::Post,
        "/admin/impersonate-user",
        "admin_impersonate_user",
        "admin.impersonate_user",
    ),
    (
        HttpMethod::Post,
        "/admin/stop-impersonating",
        "admin_stop_impersonating",
        "admin.stop_impersonating",
    ),
    (
        HttpMethod::Post,
        "/admin/revoke-user-session",
        "admin_revoke_user_session",
        "admin.revoke_user_session",
    ),
    (
        HttpMethod::Post,
        "/admin/revoke-user-sessions",
        "admin_revoke_user_sessions",
        "admin.revoke_user_sessions",
    ),
    (
        HttpMethod::Post,
        "/admin/remove-user",
        "admin_remove_user",
        "admin.remove_user",
    ),
    (
        HttpMethod::Post,
        "/admin/set-user-password",
        "admin_set_user_password",
        "admin.set_user_password",
    ),
    (
        HttpMethod::Post,
        "/admin/has-permission",
        "admin_has_permission",
        "admin.has_permission",
    ),
    (
        HttpMethod::Get,
        "/admin/grant/list",
        "admin_grant_list",
        "admin.grant.list",
    ),
    (
        HttpMethod::Get,
        "/admin/rights/catalog",
        "admin_rights_catalog",
        "admin.grant.list",
    ),
    (
        HttpMethod::Get,
        "/admin/grant-assignment/list",
        "admin_grant_assignment_list",
        "admin.grant_assignment.list",
    ),
    (
        HttpMethod::Get,
        "/admin/rights/assignment/list",
        "admin_rights_assignment_list",
        "admin.rights.assignment.list",
    ),
    (
        HttpMethod::Post,
        "/admin/grant-assignment/replace-source",
        "admin_grant_assignment_replace_source",
        "admin.grant_assignment.replace_source",
    ),
    (
        HttpMethod::Post,
        "/admin/rights/assignment/replace-source",
        "admin_rights_assignment_replace_source",
        "admin.rights.assignment.replace_source",
    ),
    (
        HttpMethod::Post,
        "/admin/grant-assignment/sync-source",
        "admin_grant_assignment_sync_source",
        "admin.grant_assignment.sync_source",
    ),
    (
        HttpMethod::Post,
        "/admin/rights/assignment/sync-source",
        "admin_rights_assignment_sync_source",
        "admin.rights.assignment.sync_source",
    ),
    (
        HttpMethod::Post,
        "/admin/rights/sync-source",
        "admin_rights_sync_source",
        "admin.rights.sync_source",
    ),
    (
        HttpMethod::Post,
        "/admin/grant-assignment/sync-billing",
        "admin_grant_assignment_sync_billing",
        "admin.grant_assignment.sync_billing",
    ),
    (
        HttpMethod::Post,
        "/admin/rights/assignment/sync-billing",
        "admin_rights_assignment_sync_billing",
        "admin.rights.assignment.sync_billing",
    ),
    (
        HttpMethod::Post,
        "/admin/rights/sync-billing",
        "admin_rights_sync_billing",
        "admin.rights.sync_billing",
    ),
    (
        HttpMethod::Post,
        "/admin/api-key/create",
        "admin_api_key_create",
        "admin.api_key.create",
    ),
    (
        HttpMethod::Post,
        "/admin/athena-client/create",
        "admin_athena_client_create",
        "admin.athena_client.create",
    ),
    (
        HttpMethod::Get,
        "/admin/athena-client/list",
        "admin_athena_client_list",
        "admin.athena_client.list",
    ),
    (
        HttpMethod::Post,
        "/admin/oauth-client/create",
        "admin_oauth_client_create",
        "admin.oauth_client.create",
    ),
    (
        HttpMethod::Get,
        "/admin/oauth-client/list",
        "admin_oauth_client_list",
        "admin.oauth_client.list",
    ),
    (
        HttpMethod::Get,
        "/admin/audit-log/list",
        "admin_audit_log_list",
        "admin.audit_log.list",
    ),
    (
        HttpMethod::Get,
        "/admin/email/list",
        "admin_email_list",
        "admin.email.list",
    ),
    (
        HttpMethod::Get,
        "/admin/email/get",
        "admin_email_get",
        "admin.email.get",
    ),
    (
        HttpMethod::Post,
        "/admin/email/create",
        "admin_email_create",
        "admin.email.create",
    ),
    (
        HttpMethod::Post,
        "/admin/email/update",
        "admin_email_update",
        "admin.email.update",
    ),
    (
        HttpMethod::Post,
        "/admin/email/delete",
        "admin_email_delete",
        "admin.email.delete",
    ),
    (
        HttpMethod::Get,
        "/admin/email-failure/list",
        "admin_email_failure_list",
        "admin.email_failure.list",
    ),
    (
        HttpMethod::Post,
        "/admin/email-failure/create",
        "admin_email_failure_create",
        "admin.email_failure.create",
    ),
    (
        HttpMethod::Get,
        "/admin/email-failure/get",
        "admin_email_failure_get",
        "admin.email_failure.get",
    ),
    (
        HttpMethod::Post,
        "/admin/email-failure/update",
        "admin_email_failure_update",
        "admin.email_failure.update",
    ),
    (
        HttpMethod::Post,
        "/admin/email-failure/delete",
        "admin_email_failure_delete",
        "admin.email_failure.delete",
    ),
    (
        HttpMethod::Post,
        "/admin/email-template/create",
        "admin_email_template_create",
        "admin.email_template.create",
    ),
    (
        HttpMethod::Get,
        "/admin/email-template/list",
        "admin_email_template_list",
        "admin.email_template.list",
    ),
    (
        HttpMethod::Get,
        "/admin/email-template/get",
        "admin_email_template_get",
        "admin.email_template.get",
    ),
    (
        HttpMethod::Post,
        "/admin/email-template/update",
        "admin_email_template_update",
        "admin.email_template.update",
    ),
    (
        HttpMethod::Post,
        "/admin/email-template/delete",
        "admin_email_template_delete",
        "admin.email_template.delete",
    ),
    (
        HttpMethod::Post,
        "/admin/email-template/send",
        "admin_email_template_send",
        "admin.email_template.send",
    ),
    (
        HttpMethod::Get,
        "/admin/email-event-type/list",
        "admin_email_event_type_list",
        "admin.email_event_type.list",
    ),
];

#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
impl<DB: DatabaseAdapter> AuthPlugin<DB> for AdminPlugin {
    fn name(&self) -> &'static str {
        "admin"
    }

    fn routes(&self) -> Vec<AuthRoute> {
        ADMIN_ROUTES
            .iter()
            .map(|(method, path, operation_id, _)| {
                AuthRoute::new(method.clone(), *path, *operation_id)
            })
            .collect()
    }

    async fn on_request(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<Option<AuthResponse>> {
        let action = self.route_action(req.method(), req.path());
        if action.is_none() {
            return Ok(None);
        }

        let result = self.dispatch_admin_route(req, ctx).await;

        if let Some(action_name) = action {
            self.audit_failure_if_needed(req, ctx, action_name, &result)
                .await;
        }

        result
    }
}

// ---------------------------------------------------------------------------
// Handler implementations (old -- delegate to core)
// ---------------------------------------------------------------------------

impl AdminPlugin {
    pub fn with_grant_catalog(
        mut self,
        grant_catalog: Vec<athena_auth_core::GrantDescriptor>,
    ) -> Self {
        self.config.grant_catalog = grant_catalog;
        self
    }

    pub fn with_native_right_catalog(
        mut self,
        native_right_catalog: Vec<athena_rights::AthenaRightDescriptor>,
    ) -> Self {
        self.config.native_right_catalog = native_right_catalog;
        self
    }

    pub fn with_native_right_domain_contracts(
        mut self,
        native_right_domain_contracts: std::collections::BTreeMap<String, serde_json::Value>,
    ) -> Self {
        self.config.native_right_domain_contracts = native_right_domain_contracts;
        self
    }

    fn request_header_case_insensitive<'a>(req: &'a AuthRequest, name: &str) -> Option<&'a str> {
        req.headers
            .iter()
            .find(|(header_name, _)| header_name.eq_ignore_ascii_case(name))
            .map(|(_, header_value)| header_value.as_str())
    }

    fn hash_api_key(key: &str) -> String {
        let mut hasher = Sha256::new();
        hasher.update(key.as_bytes());
        let digest = hasher.finalize();
        base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(digest)
    }

    async fn lookup_request_api_key<DB: DatabaseAdapter>(
        &self,
        ctx: &AuthContext<DB>,
        raw_key: &str,
    ) -> AuthResult<Option<DB::ApiKey>> {
        if let Some(api_key) = ctx.database.get_api_key_by_hash(raw_key).await? {
            return Ok(Some(api_key));
        }

        let hashed = Self::hash_api_key(raw_key);
        ctx.database.get_api_key_by_hash(&hashed).await
    }

    async fn request_api_key_audit_details<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<(Option<String>, Vec<String>)> {
        let mut candidates = Vec::new();

        if let Some(raw_key) = Self::request_header_case_insensitive(req, "x-api-key")
            .map(str::trim)
            .filter(|value| !value.is_empty())
        {
            candidates.push(raw_key.to_string());
        }

        if let Some(bearer_token) = Self::request_header_case_insensitive(req, "authorization")
            .and_then(|value| value.strip_prefix("Bearer "))
            .map(str::trim)
            .filter(|value| !value.is_empty())
        {
            let bearer = bearer_token.to_string();
            if !candidates.iter().any(|candidate| candidate == &bearer) {
                candidates.push(bearer);
            }
        }

        let native_right_catalog = self.config.merged_native_right_catalog();

        for raw_key in candidates {
            if let Some(api_key) = self.lookup_request_api_key(ctx, &raw_key).await? {
                let grant_keys = stored_api_key_grant_keys(api_key.metadata());
                let granted_rights = if native_right_catalog.is_empty() {
                    grant_keys.clone()
                } else {
                    native_right_keys_for_grant_keys(
                        grant_keys.iter().map(String::as_str),
                        &native_right_catalog,
                    )
                };
                return Ok((Some(raw_key), granted_rights));
            }
        }

        Ok((None, Vec::new()))
    }

    fn resolve_tenant_for_audit(req: &AuthRequest) -> Option<String> {
        ["x-athena-tenant", "x-tenant-id", "x-tenant"]
            .iter()
            .find_map(|header_name| {
                Self::request_header_case_insensitive(req, header_name)
                    .map(str::trim)
                    .filter(|value| !value.is_empty())
                    .map(std::string::ToString::to_string)
            })
    }

    fn enrich_audit_metadata(
        &self,
        req: &AuthRequest,
        metadata: Option<serde_json::Value>,
    ) -> Option<serde_json::Value> {
        let mut enriched = serde_json::Map::new();
        enriched.insert(
            "source".to_string(),
            serde_json::Value::String("admin.on_request".to_string()),
        );
        enriched.insert(
            "method".to_string(),
            serde_json::to_value(req.method()).unwrap_or(serde_json::Value::Null),
        );
        enriched.insert(
            "path".to_string(),
            serde_json::Value::String(req.path().to_string()),
        );

        if let Some(tenant) = Self::resolve_tenant_for_audit(req) {
            enriched.insert("tenant".to_string(), serde_json::Value::String(tenant));
        }

        match metadata {
            Some(serde_json::Value::Object(object)) => {
                for (key, value) in object {
                    if !enriched.contains_key(&key) {
                        enriched.insert(key, value);
                    }
                }
            }
            Some(other) => {
                enriched.insert("details".to_string(), other);
            }
            None => {}
        }

        Some(serde_json::Value::Object(enriched))
    }

    fn route_action(&self, method: &HttpMethod, path: &str) -> Option<&'static str> {
        ADMIN_ROUTES
            .iter()
            .find(|(route_method, route_path, _, _)| route_method == method && *route_path == path)
            .map(|(_, _, _, action)| *action)
    }

    fn list_grant_assignment_action(path: &str) -> &'static str {
        match path {
            "/admin/rights/assignment/list" => "admin.rights.assignment.list",
            _ => "admin.grant_assignment.list",
        }
    }

    fn replace_grant_assignment_action(path: &str) -> &'static str {
        match path {
            "/admin/rights/assignment/replace-source" => "admin.rights.assignment.replace_source",
            _ => "admin.grant_assignment.replace_source",
        }
    }

    fn sync_grant_assignment_action(path: &str) -> &'static str {
        match path {
            "/admin/rights/assignment/sync-source" => "admin.rights.assignment.sync_source",
            "/admin/rights/sync-source" => "admin.rights.sync_source",
            _ => "admin.grant_assignment.sync_source",
        }
    }

    fn sync_billing_assignment_action(path: &str) -> &'static str {
        match path {
            "/admin/rights/assignment/sync-billing" => "admin.rights.assignment.sync_billing",
            "/admin/rights/sync-billing" => "admin.rights.sync_billing",
            _ => "admin.grant_assignment.sync_billing",
        }
    }

    async fn dispatch_admin_route<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<Option<AuthResponse>> {
        let response = match (req.method(), req.path()) {
            (&HttpMethod::Post, "/admin/set-role") => self.handle_set_role(req, ctx).await?,
            (&HttpMethod::Post, "/admin/create-user") => self.handle_create_user(req, ctx).await?,
            (&HttpMethod::Get, "/admin/list-users") => self.handle_list_users(req, ctx).await?,
            (&HttpMethod::Post, "/admin/list-user-sessions") => {
                self.handle_list_user_sessions(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/ban-user") => self.handle_ban_user(req, ctx).await?,
            (&HttpMethod::Post, "/admin/unban-user") => self.handle_unban_user(req, ctx).await?,
            (&HttpMethod::Post, "/admin/impersonate-user") => {
                self.handle_impersonate_user(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/stop-impersonating") => {
                self.handle_stop_impersonating(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/revoke-user-session") => {
                self.handle_revoke_user_session(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/revoke-user-sessions") => {
                self.handle_revoke_user_sessions(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/remove-user") => self.handle_remove_user(req, ctx).await?,
            (&HttpMethod::Post, "/admin/set-user-password") => {
                self.handle_set_user_password(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/has-permission") => {
                self.handle_has_permission(req, ctx).await?
            }
            (&HttpMethod::Get, "/admin/grant/list")
            | (&HttpMethod::Get, "/admin/rights/catalog") => {
                self.handle_list_grants(req, ctx).await?
            }
            (&HttpMethod::Get, "/admin/grant-assignment/list") => {
                self.handle_list_grant_assignments(req, ctx).await?
            }
            (&HttpMethod::Get, "/admin/rights/assignment/list") => {
                self.handle_list_grant_assignments(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/grant-assignment/replace-source") => {
                self.handle_replace_grant_assignments_for_source(req, ctx)
                    .await?
            }
            (&HttpMethod::Post, "/admin/rights/assignment/replace-source") => {
                self.handle_replace_grant_assignments_for_source(req, ctx)
                    .await?
            }
            (&HttpMethod::Post, "/admin/grant-assignment/sync-source") => {
                self.handle_sync_grant_assignments(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/rights/assignment/sync-source") => {
                self.handle_sync_grant_assignments(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/rights/sync-source") => {
                self.handle_sync_native_right_assignments(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/grant-assignment/sync-billing") => {
                self.handle_sync_billing_grant_assignments(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/rights/assignment/sync-billing") => {
                self.handle_sync_billing_right_assignments(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/rights/sync-billing") => {
                self.handle_sync_billing_right_assignments(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/api-key/create") => {
                self.handle_create_admin_api_key(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/athena-client/create") => {
                self.handle_create_athena_client(req, ctx).await?
            }
            (&HttpMethod::Get, "/admin/athena-client/list") => {
                self.handle_list_athena_clients(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/oauth-client/create") => {
                self.handle_create_oauth_client(req, ctx).await?
            }
            (&HttpMethod::Get, "/admin/oauth-client/list") => {
                self.handle_list_oauth_clients(req, ctx).await?
            }
            (&HttpMethod::Get, "/admin/audit-log/list") => {
                self.handle_list_audit_logs(req, ctx).await?
            }
            (&HttpMethod::Get, "/admin/email/list") => {
                self.handle_list_sent_emails(req, ctx).await?
            }
            (&HttpMethod::Get, "/admin/email/get") => self.handle_get_sent_email(req, ctx).await?,
            (&HttpMethod::Post, "/admin/email/create") => {
                self.handle_create_sent_email(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/email/update") => {
                self.handle_update_sent_email(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/email/delete") => {
                self.handle_delete_sent_email(req, ctx).await?
            }
            (&HttpMethod::Get, "/admin/email-failure/list") => {
                self.handle_list_email_send_failures(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/email-failure/create") => {
                self.handle_create_email_send_failure(req, ctx).await?
            }
            (&HttpMethod::Get, "/admin/email-failure/get") => {
                self.handle_get_email_send_failure(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/email-failure/update") => {
                self.handle_update_email_send_failure(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/email-failure/delete") => {
                self.handle_delete_email_send_failure(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/email-template/create") => {
                self.handle_create_email_template(req, ctx).await?
            }
            (&HttpMethod::Get, "/admin/email-template/list") => {
                self.handle_list_email_templates(req, ctx).await?
            }
            (&HttpMethod::Get, "/admin/email-template/get") => {
                self.handle_get_email_template(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/email-template/update") => {
                self.handle_update_email_template(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/email-template/delete") => {
                self.handle_delete_email_template(req, ctx).await?
            }
            (&HttpMethod::Post, "/admin/email-template/send") => {
                self.handle_send_email_template(req, ctx).await?
            }
            (&HttpMethod::Get, "/admin/email-event-type/list") => {
                self.handle_list_email_event_types(req, ctx).await?
            }
            _ => return Ok(None),
        };

        Ok(Some(response))
    }

    async fn resolve_actor_user_id<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> Option<String> {
        if let Some(virtual_user_id) = req.virtual_user_id() {
            return Some(virtual_user_id.to_string());
        }

        let session_manager = ctx.session_manager();
        let token = session_manager.extract_session_token(req)?;
        let session = session_manager.get_session(&token).await.ok()??;
        Some(session.user_id().to_string())
    }

    async fn audit_failure_if_needed<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
        action: &str,
        result: &AuthResult<Option<AuthResponse>>,
    ) {
        let (status, error_message) = match result {
            Err(err) => (None, err.to_string()),
            Ok(Some(resp)) if resp.status >= 400 => (
                Some(resp.status),
                format!("Admin request returned HTTP {}", resp.status),
            ),
            _ => return,
        };

        let actor_user_id = self.resolve_actor_user_id(req, ctx).await;
        let metadata = serde_json::json!({
            "status": status,
            "errorClass": if status.is_some() { "http" } else { "internal" },
        });

        self.write_audit(
            req,
            ctx,
            actor_user_id.as_deref(),
            action,
            None,
            None,
            false,
            Some(error_message),
            Some(metadata),
        )
        .await;
    }

    #[allow(clippy::too_many_arguments)]
    async fn write_audit<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
        actor_user_id: Option<&str>,
        action: &str,
        target_type: Option<&str>,
        target_id: Option<&str>,
        success: bool,
        error_message: Option<String>,
        metadata: Option<serde_json::Value>,
    ) {
        let actor_session_token = ctx.session_manager().extract_session_token(req);
        let metadata = self.enrich_audit_metadata(req, metadata);
        let trace_id = request_trace_id_from_auth_request(req);
        let (api_key, granted_rights) = self
            .request_api_key_audit_details(req, ctx)
            .await
            .unwrap_or_else(|_| (None, Vec::new()));
        let event = CreateAdminAuditLog {
            actor_user_id: actor_user_id.map(std::string::ToString::to_string),
            actor_session_token,
            trace_id: Some(trace_id),
            api_key,
            action: action.to_string(),
            target_type: target_type.map(std::string::ToString::to_string),
            target_id: target_id.map(std::string::ToString::to_string),
            success,
            error_message,
            granted_rights,
            requested_rights: vec![action.to_string()],
            metadata,
        };

        if let Err(err) = ctx.database.create_admin_audit_log(event).await {
            tracing::error!(
                action = %action,
                error = %err,
                "Failed to persist admin audit log"
            );
        }
    }

    fn has_permission_audit_target(
        body: &HasPermissionRequest,
    ) -> (Option<&'static str>, Option<String>) {
        if let Some(permissions) = body.permissions.as_ref() {
            return (Some("permissions"), serde_json::to_string(permissions).ok());
        }

        if let Some(permission) = body.permission.as_ref() {
            return (Some("permission"), serde_json::to_string(permission).ok());
        }

        if !body.grant_keys.is_empty() {
            return (
                Some("grantKeys"),
                serde_json::to_string(&body.grant_keys).ok(),
            );
        }

        if !body.right_keys.is_empty() {
            return (
                Some("rightKeys"),
                serde_json::to_string(&body.right_keys).ok(),
            );
        }

        if !body.right_modules.is_empty() {
            return (
                Some("rightModules"),
                serde_json::to_string(&body.right_modules).ok(),
            );
        }

        (None, None)
    }

    /// Authenticate the caller and verify they have the admin role.
    async fn require_admin<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<(DB::User, DB::Session)> {
        let (user, session) = ctx.require_session(req).await?;

        let user_role = user.role().unwrap_or("user");
        if user_role != self.config.admin_role {
            return Err(AuthError::forbidden(
                "You do not have permission to access this resource",
            ));
        }

        Ok((user, session))
    }

    async fn require_admin_or_audit<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
        _action: &str,
    ) -> AuthResult<(DB::User, DB::Session)> {
        self.require_admin(req, ctx).await
    }

    async fn handle_set_role<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.set_role")
            .await?;
        let body: SetRoleRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = set_role_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.set_role",
            Some("user"),
            Some(&body.user_id),
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_create_user<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.create_user")
            .await?;
        let body: CreateUserRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = create_user_core(&body, &self.config, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.create_user",
            Some("user"),
            response.user.email(),
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_list_users<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.list_users")
            .await?;
        let query = ListUsersQueryParams {
            limit: req.query.get("limit").and_then(|v| v.parse().ok()),
            offset: req.query.get("offset").and_then(|v| v.parse().ok()),
            search_field: req.query.get("searchField").cloned(),
            search_value: req.query.get("searchValue").cloned(),
            search_operator: req.query.get("searchOperator").cloned(),
            sort_by: req.query.get("sortBy").cloned(),
            sort_direction: req.query.get("sortDirection").cloned(),
            filter_field: req.query.get("filterField").cloned(),
            filter_value: req.query.get("filterValue").cloned(),
            filter_operator: req.query.get("filterOperator").cloned(),
        };
        let response = list_users_core(&query, &self.config, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.list_users",
            None,
            None,
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_list_user_sessions<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.list_user_sessions")
            .await?;
        let body: UserIdRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = list_user_sessions_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.list_user_sessions",
            Some("user"),
            Some(&body.user_id),
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_ban_user<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.ban_user")
            .await?;
        let body: BanUserRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = ban_user_core(&body, admin_user.id(), &self.config, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.ban_user",
            Some("user"),
            Some(&body.user_id),
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_unban_user<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.unban_user")
            .await?;
        let body: UserIdRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = unban_user_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.unban_user",
            Some("user"),
            Some(&body.user_id),
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_impersonate_user<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.impersonate_user")
            .await?;
        let body: UserIdRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let (response, token) = impersonate_user_core(
            &body,
            admin_user.id(),
            req.headers.get("x-forwarded-for").map(|s| s.as_str()),
            req.headers.get("user-agent").map(|s| s.as_str()),
            ctx,
        )
        .await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.impersonate_user",
            Some("user"),
            Some(&body.user_id),
            true,
            None,
            None,
        )
        .await;
        let cookie_header = create_session_cookie(&token, &ctx.config);
        Ok(AuthResponse::json(200, &response)?.with_header("Set-Cookie", cookie_header))
    }

    async fn handle_stop_impersonating<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let session_manager = ctx.session_manager();
        let token = session_manager
            .extract_session_token(req)
            .ok_or(AuthError::Unauthenticated)?;
        let session = session_manager
            .get_session(&token)
            .await?
            .ok_or(AuthError::Unauthenticated)?;
        let (response, new_token) = stop_impersonating_core(
            &session,
            &token,
            req.headers.get("x-forwarded-for").map(|s| s.as_str()),
            req.headers.get("user-agent").map(|s| s.as_str()),
            ctx,
        )
        .await?;
        self.write_audit(
            req,
            ctx,
            session.impersonated_by(),
            "admin.stop_impersonating",
            Some("session"),
            Some(session.id()),
            true,
            None,
            None,
        )
        .await;
        let cookie_header = create_session_cookie(&new_token, &ctx.config);
        Ok(AuthResponse::json(200, &response)?.with_header("Set-Cookie", cookie_header))
    }

    async fn handle_revoke_user_session<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.revoke_user_session")
            .await?;
        let body: RevokeSessionRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = revoke_user_session_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.revoke_user_session",
            Some("session"),
            Some(&body.session_token),
            true,
            None,
            None,
        )
        .await;
        let response = AuthResponse::json(200, &response).map_err(AuthError::from)?;
        if body.session_token == admin_session.token() {
            let clear_cookie = create_clear_session_cookie(&ctx.config);
            return Ok(response.with_header("Set-Cookie", clear_cookie));
        }
        Ok(response)
    }

    async fn handle_revoke_user_sessions<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.revoke_user_sessions")
            .await?;
        let body: UserIdRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = revoke_user_sessions_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.revoke_user_sessions",
            Some("user"),
            Some(&body.user_id),
            true,
            None,
            None,
        )
        .await;
        let response = AuthResponse::json(200, &response).map_err(AuthError::from)?;
        if body.user_id == admin_user.id() {
            let clear_cookie = create_clear_session_cookie(&ctx.config);
            return Ok(response.with_header("Set-Cookie", clear_cookie));
        }
        Ok(response)
    }

    async fn handle_remove_user<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.remove_user")
            .await?;
        let body: UserIdRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = remove_user_core(&body, admin_user.id(), ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.remove_user",
            Some("user"),
            Some(&body.user_id),
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_set_user_password<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.set_user_password")
            .await?;
        let body: SetUserPasswordRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = set_user_password_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.set_user_password",
            Some("user"),
            Some(&body.user_id),
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_has_permission<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (user, _session) = ctx.require_session(req).await?;
        let body: HasPermissionRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = has_permission_core::<DB>(&body, &user, &self.config).await?;
        let (target_type, target_id) = Self::has_permission_audit_target(&body);
        self.write_audit(
            req,
            ctx,
            Some(user.id()),
            "admin.has_permission",
            target_type,
            target_id.as_deref(),
            response.success,
            response.error.clone(),
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_list_grants<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.grant.list")
            .await?;
        let response = list_grants_core(&self.config).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.grant.list",
            Some("grant_catalog"),
            None,
            true,
            None,
            Some(serde_json::json!({
                "grantCount": response.grant_catalog.len(),
                "nativeRightCount": response.native_rights.len(),
            })),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_list_grant_assignments<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let action = Self::list_grant_assignment_action(req.path());
        let (admin_user, _admin_session) = self.require_admin_or_audit(req, ctx, action).await?;
        let query = ListGrantAssignmentsQueryParams {
            subject_kind: req.query.get("subjectKind").cloned().unwrap_or_default(),
            subject_id: req.query.get("subjectId").cloned().unwrap_or_default(),
        };
        let response = list_grant_assignments_core(&query, &self.config, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            action,
            Some("grant_assignment_subject"),
            Some(&format!("{}:{}", query.subject_kind, query.subject_id)),
            true,
            None,
            Some(serde_json::json!({
                "subjectKind": query.subject_kind,
                "subjectId": query.subject_id,
                "grantCount": response.grant_assignments.len(),
                "resolvedGrantCount": response.resolved_grants.len(),
                "unknownGrantKeys": response.unknown_grant_keys,
            })),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_replace_grant_assignments_for_source<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let action = Self::replace_grant_assignment_action(req.path());
        let (admin_user, _admin_session) = self.require_admin_or_audit(req, ctx, action).await?;
        let body: ReplaceGrantAssignmentsForSourceRequest =
            match athena_auth_core::validate_request_body(req) {
                Ok(v) => v,
                Err(resp) => return Ok(resp),
            };
        let response = replace_grant_assignments_for_source_core(&body, &self.config, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            action,
            Some("grant_assignment_source"),
            Some(&format!(
                "{}:{}:{}:{}",
                response.subject_kind,
                response.subject_id,
                response.source_kind,
                response.source_ref
            )),
            true,
            None,
            Some(serde_json::json!({
                "subjectKind": response.subject_kind,
                "subjectId": response.subject_id,
                "sourceKind": response.source_kind,
                "sourceRef": response.source_ref,
                "appliedGrantKeys": response.applied_grant_keys,
                "replacedAssignmentCount": response.replaced_assignments.len(),
                "subjectGrantCount": response.subject_state.grant_assignments.len(),
                "unknownGrantKeys": response.subject_state.unknown_grant_keys,
            })),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_sync_billing_grant_assignments<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let action = Self::sync_billing_assignment_action(req.path());
        let (admin_user, _admin_session) = self.require_admin_or_audit(req, ctx, action).await?;
        let body: SyncBillingGrantAssignmentsRequest =
            match athena_auth_core::validate_request_body(req) {
                Ok(v) => v,
                Err(resp) => return Ok(resp),
            };
        let response = sync_billing_grant_assignments_core(&body, &self.config, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            action,
            Some("billing_grant_assignment_source"),
            Some(&format!(
                "{}:{}:{}:{}",
                response.subject_kind,
                response.subject_id,
                response.source_kind,
                response.source_ref
            )),
            true,
            None,
            Some(serde_json::json!({
                "subjectKind": response.subject_kind,
                "subjectId": response.subject_id,
                "sourceKind": response.source_kind,
                "sourceRef": response.source_ref,
                "appliedGrantKeys": response.applied_grant_keys,
                "replacedAssignmentCount": response.replaced_assignments.len(),
                "subjectGrantCount": response.subject_state.grant_assignments.len(),
                "unknownGrantKeys": response.subject_state.unknown_grant_keys,
                "source": "billing",
            })),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_sync_billing_right_assignments<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let action = Self::sync_billing_assignment_action(req.path());
        let (admin_user, _admin_session) = self.require_admin_or_audit(req, ctx, action).await?;
        let body: SyncBillingRightAssignmentsRequest =
            match athena_auth_core::validate_request_body(req) {
                Ok(v) => v,
                Err(resp) => return Ok(resp),
            };
        let response = sync_billing_right_assignments_core(&body, &self.config, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            action,
            Some("billing_grant_assignment_source"),
            Some(&format!(
                "{}:{}:{}:{}",
                response.subject_kind,
                response.subject_id,
                response.source_kind,
                response.source_ref
            )),
            true,
            None,
            Some(serde_json::json!({
                "subjectKind": response.subject_kind,
                "subjectId": response.subject_id,
                "sourceKind": response.source_kind,
                "sourceRef": response.source_ref,
                "grantKeys": response.applied_grant_keys,
                "rightKeys": response.applied_right_keys,
            })),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_sync_grant_assignments<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let action = Self::sync_grant_assignment_action(req.path());
        let (admin_user, _admin_session) = self.require_admin_or_audit(req, ctx, action).await?;
        let body: SyncGrantAssignmentsRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = sync_grant_assignments_core(&body, &self.config, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            action,
            Some("grant_assignment_source"),
            Some(&format!(
                "{}:{}:{}:{}",
                response.subject_kind,
                response.subject_id,
                response.source_kind,
                response.source_ref
            )),
            true,
            None,
            Some(serde_json::json!({
                "subjectKind": response.subject_kind,
                "subjectId": response.subject_id,
                "sourceKind": response.source_kind,
                "sourceRef": response.source_ref,
                "appliedGrantKeys": response.applied_grant_keys,
                "replacedAssignmentCount": response.replaced_assignments.len(),
                "subjectGrantCount": response.subject_state.grant_assignments.len(),
                "unknownGrantKeys": response.subject_state.unknown_grant_keys,
            })),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_sync_native_right_assignments<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let action = Self::sync_grant_assignment_action(req.path());
        let (admin_user, _admin_session) = self.require_admin_or_audit(req, ctx, action).await?;
        let body: SyncNativeRightAssignmentsRequest =
            match athena_auth_core::validate_request_body(req) {
                Ok(v) => v,
                Err(resp) => return Ok(resp),
            };
        let response = sync_native_right_assignments_core(&body, &self.config, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            action,
            Some("native_right_assignment_source"),
            Some(&format!(
                "{}:{}:{}:{}",
                response.subject_kind,
                response.subject_id,
                response.source_kind,
                response.source_ref
            )),
            true,
            None,
            Some(serde_json::json!({
                "subjectKind": response.subject_kind,
                "subjectId": response.subject_id,
                "sourceKind": response.source_kind,
                "sourceRef": response.source_ref,
                "appliedGrantKeys": response.applied_grant_keys,
                "appliedRightKeys": response.applied_right_keys,
                "replacedAssignmentCount": response.replaced_assignments.len(),
                "subjectGrantCount": response.subject_state.grant_assignments.len(),
                "unknownGrantKeys": response.subject_state.unknown_grant_keys,
                "unknownRightKeys": response.subject_state.unknown_right_keys,
            })),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_create_admin_api_key<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.api_key.create")
            .await?;
        let body: CreateAdminApiKeyRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = create_admin_api_key_core(&body, &self.config, &admin_user, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.api_key.create",
            Some("api_key"),
            Some(&response.api_key.id),
            true,
            None,
            body.metadata.clone(),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_create_athena_client<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.athena_client.create")
            .await?;
        let body: CreateAthenaClientRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = create_athena_client_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.athena_client.create",
            Some("athena_client"),
            Some(&response.client_name),
            true,
            None,
            body.metadata.clone(),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_list_athena_clients<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.athena_client.list")
            .await?;
        let response = list_athena_clients_core(ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.athena_client.list",
            None,
            None,
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_create_oauth_client<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.oauth_client.create")
            .await?;
        let body: CreateOAuthClientRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = create_oauth_client_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.oauth_client.create",
            Some("oauth_client"),
            Some(&response.client_name),
            true,
            None,
            body.metadata.clone(),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_list_oauth_clients<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.oauth_client.list")
            .await?;
        let response = list_oauth_clients_core(ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.oauth_client.list",
            None,
            None,
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_list_audit_logs<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.audit_log.list")
            .await?;
        let query = ListAuditLogsQueryParams {
            limit: req.query.get("limit").and_then(|v| v.parse().ok()),
            offset: req.query.get("offset").and_then(|v| v.parse().ok()),
            actor_user_id: req.query.get("actorUserId").cloned(),
            action: req.query.get("action").cloned(),
            target_type: req.query.get("targetType").cloned(),
            target_id: req.query.get("targetId").cloned(),
            success: req.query.get("success").and_then(|v| v.parse().ok()),
            created_after: req.query.get("createdAfter").cloned(),
            created_before: req.query.get("createdBefore").cloned(),
        };
        let response = list_audit_logs_core(&query, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.audit_log.list",
            None,
            None,
            true,
            None,
            Some(serde_json::json!({
                "limit": query.limit,
                "offset": query.offset,
                "actorUserId": query.actor_user_id,
                "action": query.action,
                "targetType": query.target_type,
                "targetId": query.target_id,
                "success": query.success,
                "createdAfter": query.created_after,
                "createdBefore": query.created_before,
            })),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_list_sent_emails<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email.list")
            .await?;
        let query = ListSentEmailsQueryParams {
            limit: req.query.get("limit").and_then(|v| v.parse().ok()),
            offset: req.query.get("offset").and_then(|v| v.parse().ok()),
            recipient_email: req.query.get("recipientEmail").cloned(),
            provider: req.query.get("provider").cloned(),
            flow: req.query.get("flow").cloned(),
            subject_contains: req.query.get("subjectContains").cloned(),
            created_after: req.query.get("createdAfter").cloned(),
            created_before: req.query.get("createdBefore").cloned(),
        };
        let response = list_sent_emails_core(&query, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email.list",
            None,
            None,
            true,
            None,
            Some(serde_json::json!({
                "limit": query.limit,
                "offset": query.offset,
                "recipientEmail": query.recipient_email,
                "provider": query.provider,
                "flow": query.flow,
                "subjectContains": query.subject_contains,
                "createdAfter": query.created_after,
                "createdBefore": query.created_before,
            })),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_get_sent_email<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email.get")
            .await?;
        let query = GetSentEmailQueryParams {
            id: req.query.get("id").cloned().unwrap_or_default(),
        };
        let response = get_sent_email_core(&query, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email.get",
            Some("email"),
            Some(&query.id),
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_create_sent_email<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email.create")
            .await?;
        let body: CreateSentEmailRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = create_sent_email_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email.create",
            Some("email"),
            Some(&response.email.id),
            true,
            None,
            body.metadata.clone(),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_update_sent_email<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email.update")
            .await?;
        let body: UpdateSentEmailRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = update_sent_email_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email.update",
            Some("email"),
            Some(&body.id),
            true,
            None,
            body.metadata.clone(),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_delete_sent_email<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email.delete")
            .await?;
        let body: DeleteSentEmailRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = delete_sent_email_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email.delete",
            Some("email"),
            Some(&body.id),
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_list_email_send_failures<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email_failure.list")
            .await?;
        let query = ListEmailSendFailuresQueryParams {
            limit: req.query.get("limit").and_then(|v| v.parse().ok()),
            offset: req.query.get("offset").and_then(|v| v.parse().ok()),
            recipient_email: req.query.get("recipientEmail").cloned(),
            provider: req.query.get("provider").cloned(),
            flow: req.query.get("flow").cloned(),
            resolved: req.query.get("resolved").and_then(|v| v.parse().ok()),
            created_after: req.query.get("createdAfter").cloned(),
            created_before: req.query.get("createdBefore").cloned(),
        };
        let response = list_email_send_failures_core(&query, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email_failure.list",
            None,
            None,
            true,
            None,
            Some(serde_json::json!({
                "limit": query.limit,
                "offset": query.offset,
                "recipientEmail": query.recipient_email,
                "provider": query.provider,
                "flow": query.flow,
                "resolved": query.resolved,
                "createdAfter": query.created_after,
                "createdBefore": query.created_before,
            })),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_create_email_send_failure<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email_failure.create")
            .await?;
        let body: CreateEmailSendFailureRequest = match athena_auth_core::validate_request_body(req)
        {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = create_email_send_failure_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email_failure.create",
            Some("email_send_failure"),
            Some(&response.email_send_failure.id),
            true,
            None,
            body.metadata.clone(),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_get_email_send_failure<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email_failure.get")
            .await?;
        let query = GetEmailSendFailureQueryParams {
            id: req.query.get("id").cloned().unwrap_or_default(),
        };
        let response = get_email_send_failure_core(&query, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email_failure.get",
            Some("email_send_failure"),
            Some(&query.id),
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_update_email_send_failure<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email_failure.update")
            .await?;
        let body: UpdateEmailSendFailureRequest = match athena_auth_core::validate_request_body(req)
        {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = update_email_send_failure_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email_failure.update",
            Some("email_send_failure"),
            Some(&body.id),
            true,
            None,
            body.metadata.clone(),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_delete_email_send_failure<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email_failure.delete")
            .await?;
        let body: DeleteEmailSendFailureRequest = match athena_auth_core::validate_request_body(req)
        {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = delete_email_send_failure_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email_failure.delete",
            Some("email_send_failure"),
            Some(&body.id),
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_create_email_template<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email_template.create")
            .await?;
        let body: CreateEmailTemplateRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = create_email_template_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email_template.create",
            Some("email_template"),
            Some(&response.id),
            true,
            None,
            body.metadata.clone(),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_list_email_templates<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email_template.list")
            .await?;
        let query_value = |snake: &str, camel: &str| {
            req.query
                .get(snake)
                .cloned()
                .or_else(|| req.query.get(camel).cloned())
        };
        let query = ListEmailTemplatesQueryParams {
            limit: req.query.get("limit").and_then(|v| v.parse().ok()),
            offset: req.query.get("offset").and_then(|v| v.parse().ok()),
            template_key: query_value("template_key", "templateKey"),
            event_type: query_value("event_type", "eventType"),
            locale: query_value("locale", "locale"),
            is_active: query_value("is_active", "isActive").and_then(|v| v.parse().ok()),
        };
        let response = list_email_templates_core(&query, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email_template.list",
            None,
            None,
            true,
            None,
            Some(serde_json::json!({
                "limit": query.limit,
                "offset": query.offset,
                "template_key": query.template_key,
                "event_type": query.event_type,
                "locale": query.locale,
                "is_active": query.is_active,
            })),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_get_email_template<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email_template.get")
            .await?;
        let query = GetEmailTemplateQueryParams {
            id: req.query.get("id").cloned().unwrap_or_default(),
        };
        let response = get_email_template_core(&query, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email_template.get",
            Some("email_template"),
            Some(&query.id),
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_update_email_template<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email_template.update")
            .await?;
        let body: UpdateEmailTemplateRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = update_email_template_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email_template.update",
            Some("email_template"),
            Some(&body.id),
            true,
            None,
            body.metadata.clone(),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_delete_email_template<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email_template.delete")
            .await?;
        let body: DeleteEmailTemplateRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let response = delete_email_template_core(&body, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email_template.delete",
            Some("email_template"),
            Some(&body.id),
            true,
            None,
            None,
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }

    async fn handle_send_email_template<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email_template.send")
            .await?;
        let body: SendEmailTemplateRequest = match athena_auth_core::validate_request_body(req) {
            Ok(v) => v,
            Err(resp) => return Ok(resp),
        };
        let result = send_email_template_core(&body, ctx).await?;
        if result.response.success {
            self.write_audit(
                req,
                ctx,
                Some(admin_user.id()),
                "admin.email_template.send",
                Some("email_template"),
                Some(&result.response.template_id),
                true,
                None,
                merge_email_metadata(
                    body.metadata.clone(),
                    Some(serde_json::json!({
                        "recipient_email": result.response.recipient_email,
                        "template_key": result.response.template_key,
                        "event_type": result.response.event_type,
                        "attachment_count": result.response.attachment_count,
                        "delivery_metadata": result.response.delivery_metadata,
                    })),
                ),
            )
            .await;
        }

        AuthResponse::json(result.status, &result.response).map_err(AuthError::from)
    }

    async fn handle_list_email_event_types<DB: DatabaseAdapter>(
        &self,
        req: &AuthRequest,
        ctx: &AuthContext<DB>,
    ) -> AuthResult<AuthResponse> {
        let (admin_user, _admin_session) = self
            .require_admin_or_audit(req, ctx, "admin.email_event_type.list")
            .await?;
        let query = ListEmailEventTypesQueryParams {
            limit: req.query.get("limit").and_then(|v| v.parse().ok()),
            offset: req.query.get("offset").and_then(|v| v.parse().ok()),
            event_type: req.query.get("eventType").cloned(),
            category: req.query.get("category").cloned(),
            is_active: req.query.get("isActive").and_then(|v| v.parse().ok()),
            is_system: req.query.get("isSystem").and_then(|v| v.parse().ok()),
        };
        let response = list_email_event_types_core(&query, ctx).await?;
        self.write_audit(
            req,
            ctx,
            Some(admin_user.id()),
            "admin.email_event_type.list",
            None,
            None,
            true,
            None,
            Some(serde_json::json!({
                "limit": query.limit,
                "offset": query.offset,
                "eventType": query.event_type,
                "category": query.category,
                "isActive": query.is_active,
                "isSystem": query.is_system,
            })),
        )
        .await;
        AuthResponse::json(200, &response).map_err(AuthError::from)
    }
}

// ---------------------------------------------------------------------------
// Axum integration
// ---------------------------------------------------------------------------

#[cfg(feature = "axum")]
mod axum_impl {
    use super::*;
    use std::collections::HashMap;
    use std::sync::Arc;

    use athena_auth_core::{AdminRole, AuthState};
    use axum::body::to_bytes;
    use axum::extract::{Extension, Request, State};
    use axum::response::Response;

    #[derive(Clone)]
    struct PluginState {
        plugin: AdminPlugin,
    }

    async fn dispatch_admin_request<DB: DatabaseAdapter>(
        State(state): State<AuthState<DB>>,
        Extension(ps): Extension<Arc<PluginState>>,
        req: Request,
    ) -> Response {
        let auth_req = match convert_axum_request(req).await {
            Ok(req) => req,
            Err(err) => return convert_auth_response(err.into_response()),
        };
        let ctx = state.to_context();
        match <AdminPlugin as AuthPlugin<DB>>::on_request(&ps.plugin, &auth_req, &ctx).await {
            Ok(Some(resp)) => convert_auth_response(resp),
            Ok(None) => convert_auth_response(
                AuthError::not_found("No handler found for this request").into_response(),
            ),
            Err(err) => convert_auth_response(err.into_response()),
        }
    }

    async fn convert_axum_request(req: Request) -> AuthResult<AuthRequest> {
        let (parts, body) = req.into_parts();

        let method = match parts.method {
            axum::http::Method::GET => HttpMethod::Get,
            axum::http::Method::POST => HttpMethod::Post,
            axum::http::Method::PUT => HttpMethod::Put,
            axum::http::Method::DELETE => HttpMethod::Delete,
            axum::http::Method::PATCH => HttpMethod::Patch,
            axum::http::Method::OPTIONS => HttpMethod::Options,
            axum::http::Method::HEAD => HttpMethod::Head,
            _ => {
                return Err(AuthError::InvalidRequest(
                    "Unsupported HTTP method".to_string(),
                ));
            }
        };

        let mut headers: HashMap<String, String> = HashMap::new();
        for (name, value) in &parts.headers {
            if let Ok(value_str) = value.to_str() {
                headers.insert(name.to_string(), value_str.to_string());
            }
        }

        let path = parts.uri.path().to_string();

        let mut query: HashMap<String, String> = HashMap::new();
        if let Some(query_str) = parts.uri.query() {
            for (key, value) in url::form_urlencoded::parse(query_str.as_bytes()) {
                query.insert(key.to_string(), value.to_string());
            }
        }

        let body_bytes = match to_bytes(body, usize::MAX).await {
            Ok(bytes) if !bytes.is_empty() => Some(bytes.to_vec()),
            _ => None,
        };

        Ok(AuthRequest::from_parts(
            method, path, headers, body_bytes, query,
        ))
    }

    fn convert_auth_response(auth_response: AuthResponse) -> Response {
        let mut response: axum::http::response::Builder = Response::builder().status(
            axum::http::StatusCode::from_u16(auth_response.status)
                .unwrap_or(axum::http::StatusCode::INTERNAL_SERVER_ERROR),
        );

        for (name, value) in auth_response.headers {
            if let (Ok(header_name), Ok(header_value)) = (
                axum::http::HeaderName::from_bytes(name.as_bytes()),
                axum::http::HeaderValue::from_str(&value),
            ) {
                response = response.header(header_name, header_value);
            }
        }
        response
            .body(axum::body::Body::from(auth_response.body))
            .unwrap_or_else(|_| {
                Response::builder()
                    .status(axum::http::StatusCode::INTERNAL_SERVER_ERROR)
                    .body(axum::body::Body::from("Internal server error"))
                    .expect("building fallback error response should succeed")
            })
    }

    impl<DB: DatabaseAdapter> athena_auth_core::AxumPlugin<DB> for AdminPlugin {
        fn name(&self) -> &'static str {
            "admin"
        }

        fn router(&self) -> axum::Router<AuthState<DB>> {
            use axum::routing::{delete, get, patch, post, put};

            let plugin_state = Arc::new(PluginState {
                plugin: self.clone(),
            });
            let mut router = axum::Router::new();
            for (method, path, _, _) in ADMIN_ROUTES {
                router = match method {
                    HttpMethod::Get => router.route(path, get(dispatch_admin_request::<DB>)),
                    HttpMethod::Post => router.route(path, post(dispatch_admin_request::<DB>)),
                    HttpMethod::Put => router.route(path, put(dispatch_admin_request::<DB>)),
                    HttpMethod::Delete => router.route(path, delete(dispatch_admin_request::<DB>)),
                    HttpMethod::Patch => router.route(path, patch(dispatch_admin_request::<DB>)),
                    _ => router,
                };
            }

            router
                .layer(Extension(plugin_state))
                .layer(Extension(AdminRole(self.config.admin_role.clone())))
        }
    }
}
