use crate::db;
use crate::errors::CognitoError;
use crate::server::AppState;
use axum::response::{IntoResponse, Response};
use std::sync::Arc;

pub async fn get_user(
    body: serde_json::Value,
    state: &Arc<AppState>,
) -> Result<Response, CognitoError> {
    let access_token = body["AccessToken"]
        .as_str()
        .ok_or_else(|| CognitoError::InvalidParameter("AccessToken is required".into()))?;

    let claims = state
        .crypto
        .decode_access_token(access_token)
        .map_err(|e| CognitoError::NotAuthorized(format!("Invalid access token: {e}")))?;

    // Extract pool_id from issuer: "http://localhost:9229/us-east-1_xxx" -> "us-east-1_xxx"
    let pool_id = claims
        .iss
        .rsplit('/')
        .next()
        .ok_or_else(|| CognitoError::InternalError("Invalid token issuer".into()))?;

    let user = db::users::get(&state.db, pool_id, &claims.username)
        .map_err(|e| CognitoError::InternalError(e.to_string()))?
        .ok_or_else(|| CognitoError::UserNotFound("User not found".into()))?;

    let response = serde_json::json!({
        "Username": user.username,
        "UserAttributes": user.attributes,
    });
    Ok(axum::Json(response).into_response())
}

pub async fn global_sign_out(
    body: serde_json::Value,
    state: &Arc<AppState>,
) -> Result<Response, CognitoError> {
    let access_token = body["AccessToken"]
        .as_str()
        .ok_or_else(|| CognitoError::InvalidParameter("AccessToken is required".into()))?;

    let claims = state
        .crypto
        .decode_access_token(access_token)
        .map_err(|e| CognitoError::NotAuthorized(format!("Invalid access token: {e}")))?;

    let pool_id = claims
        .iss
        .rsplit('/')
        .next()
        .ok_or_else(|| CognitoError::InternalError("Invalid token issuer".into()))?;

    db::tokens::delete_user_tokens(&state.db, pool_id, &claims.username)
        .map_err(|e| CognitoError::InternalError(e.to_string()))?;

    Ok(axum::Json(serde_json::json!({})).into_response())
}

pub async fn admin_user_global_sign_out(
    body: serde_json::Value,
    state: &Arc<AppState>,
) -> Result<Response, CognitoError> {
    let pool_id = body["UserPoolId"]
        .as_str()
        .ok_or_else(|| CognitoError::InvalidParameter("UserPoolId is required".into()))?;
    let username = body["Username"]
        .as_str()
        .ok_or_else(|| CognitoError::InvalidParameter("Username is required".into()))?;

    db::tokens::delete_user_tokens(&state.db, pool_id, username)
        .map_err(|e| CognitoError::InternalError(e.to_string()))?;

    Ok(axum::Json(serde_json::json!({})).into_response())
}
