use axum::{
    extract::State,
    http::{header, StatusCode},
    response::Json,
};
use serde_json::json;
use std::sync::Arc;

use crate::state::AppState;

/// GET handler for UserInfo endpoint
/// Validates Bearer tokens and returns user profile information
pub async fn userinfo_handler(
    State(state): State<Arc<AppState>>,
    headers: axum::http::HeaderMap,
) -> Result<Json<serde_json::Value>, (StatusCode, Json<serde_json::Value>)> {
    // Extract Bearer token from Authorization header
    let auth_header = headers
        .get(header::AUTHORIZATION)
        .and_then(|h| h.to_str().ok())
        .ok_or_else(|| {
            (
                StatusCode::UNAUTHORIZED,
                Json(json!({
                    "error": "invalid_token",
                    "error_description": "Missing or invalid Authorization header"
                })),
            )
        })?;

    // Validate Bearer token format
    if !auth_header.starts_with("Bearer ") {
        return Err((
            StatusCode::UNAUTHORIZED,
            Json(json!({
                "error": "invalid_token",
                "error_description": "Invalid token format"
            })),
        ));
    }

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

    // Retrieve and validate the token
    let token_data = match state.get_token(token) {
        Some(data) => data,
        None => {
            return Err((
                StatusCode::UNAUTHORIZED,
                Json(json!({
                    "error": "invalid_token",
                    "error_description": "Invalid or expired access token"
                })),
            ));
        }
    };

    // Check if token has expired
    if token_data.is_expired() {
        return Err((
            StatusCode::UNAUTHORIZED,
            Json(json!({
                "error": "invalid_token",
                "error_description": "Access token has expired"
            })),
        ));
    }

    // Get the user profile
    let user = match state.users.values().find(|u| u.profile.me == token_data.me) {
        Some(user) => user,
        None => {
            return Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(json!({
                    "error": "server_error",
                    "error_description": "User profile not found"
                })),
            ));
        }
    };

    // Build profile response based on granted scopes
    let mut profile_data = serde_json::Map::new();
    
    // Always include the 'me' URL
    profile_data.insert("me".to_string(), json!(token_data.me.to_string()));

    // Include profile information based on scopes
    if token_data.scope.has("profile") {
        profile_data.insert("name".to_string(), json!(user.profile.name));
        
        if let Some(photo) = &user.profile.photo {
            profile_data.insert("photo".to_string(), json!(photo.to_string()));
        }
        
        if let Some(url) = &user.profile.url {
            profile_data.insert("url".to_string(), json!(url.to_string()));
        } else {
            profile_data.insert("url".to_string(), json!(token_data.me.to_string()));
        }
    }

    if token_data.scope.has("email") {
        if let Some(email) = &user.profile.email {
            profile_data.insert("email".to_string(), json!(email));
        }
    }

    Ok(Json(json!(profile_data)))
}

/// Alternative POST handler for token introspection
/// This can be used to validate tokens and get profile information
pub async fn introspection_handler(
    State(state): State<Arc<AppState>>,
    _headers: axum::http::HeaderMap,
    axum::Form(form): axum::Form<serde_json::Value>,
) -> Result<Json<serde_json::Value>, (StatusCode, Json<serde_json::Value>)> {
    // Extract token from form data
    let token = form.get("token")
        .and_then(|v| v.as_str())
        .ok_or_else(|| {
            (
                StatusCode::BAD_REQUEST,
                Json(json!({
                    "error": "invalid_request",
                    "error_description": "Missing token parameter"
                })),
            )
        })?;

    // Optional: Validate client credentials if provided
    // For demo purposes, we'll allow introspection without client authentication

    // Retrieve and validate the token
    let token_data = match state.get_token(token) {
        Some(data) => data,
        None => {
            return Ok(Json(json!({
                "active": false
            })));
        }
    };

    // Check if token has expired
    if token_data.is_expired() {
        return Ok(Json(json!({
            "active": false
        })));
    }

    // Get the user profile
    let user = match state.users.values().find(|u| u.profile.me == token_data.me) {
        Some(user) => user,
        None => {
            return Ok(Json(json!({
                "active": false
            })));
        }
    };

    // Build introspection response
    let mut response = serde_json::Map::new();
    response.insert("active".to_string(), json!(true));
    response.insert("scope".to_string(), json!(token_data.scope.to_string()));
    response.insert("client_id".to_string(), json!(token_data.client_id.to_string()));
    response.insert("username".to_string(), json!(user.profile.name));
    response.insert("token_type".to_string(), json!("Bearer"));
    
    // Calculate remaining time
    let now = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .unwrap()
        .as_secs();
    let remaining = token_data.expires_at.duration_since(std::time::Instant::now()).as_secs();
    let expires_at = now + remaining;

    if remaining > 0 {
        response.insert("exp".to_string(), json!(expires_at));
    }

    Ok(Json(json!(response)))
}