use std::sync::Arc;

use axum::extract::FromRequestParts;
use http::request::Parts;
use uuid::Uuid;

use crate::services::auth as auth_service;
use crate::AppState;

/// Extractor that validates the JWT from the Authorization header
/// and provides the authenticated user's identity to handlers.
#[derive(Debug, Clone)]
pub struct AuthUser {
    pub user_id: Uuid,
    pub email: String,
    pub license_id: Option<Uuid>,
    pub role: Option<String>,
    pub is_super_admin: bool,
}

impl FromRequestParts<Arc<AppState>> for AuthUser {
    type Rejection = http::StatusCode;

    async fn from_request_parts(
        parts: &mut Parts,
        state: &Arc<AppState>,
    ) -> Result<Self, Self::Rejection> {
        // Extract Bearer token from Authorization header
        let auth_header = parts
            .headers
            .get(http::header::AUTHORIZATION)
            .and_then(|v| v.to_str().ok())
            .ok_or(http::StatusCode::UNAUTHORIZED)?;

        let token = auth_header
            .strip_prefix("Bearer ")
            .ok_or(http::StatusCode::UNAUTHORIZED)?;

        // Validate JWT
        let claims = auth_service::validate_token(&state.config, token)
            .map_err(|_| http::StatusCode::UNAUTHORIZED)?;

        // Ensure it's an access token, not a refresh token
        if claims.token_type != "access" {
            return Err(http::StatusCode::UNAUTHORIZED);
        }

        Ok(AuthUser {
            user_id: claims.sub,
            email: claims.email,
            license_id: claims.license_id,
            role: claims.role,
            is_super_admin: claims.is_super_admin,
        })
    }
}

/// Extractor that requires super-admin privileges.
/// Use this on all /api/admin/* handlers.
#[derive(Debug, Clone)]
pub struct SuperAdmin {
    pub user_id: Uuid,
    pub email: String,
}

impl FromRequestParts<Arc<AppState>> for SuperAdmin {
    type Rejection = http::StatusCode;

    async fn from_request_parts(
        parts: &mut Parts,
        state: &Arc<AppState>,
    ) -> Result<Self, Self::Rejection> {
        let auth = AuthUser::from_request_parts(parts, state).await?;

        if !auth.is_super_admin {
            return Err(http::StatusCode::FORBIDDEN);
        }

        Ok(SuperAdmin {
            user_id: auth.user_id,
            email: auth.email,
        })
    }
}
