//! Inventory API handlers for user UI.
//!
//! Handles inventory listing and item management.

use axum::Json;
use axum::extract::{Path, State};
use sqlx::PgPool;
use uuid::Uuid;

use chattyness_db::{
    User,
    models::{
        AcquirePropRequest, AcquirePropResponse, InventoryResponse, PropAcquisitionListResponse,
    },
    queries::{inventory, realms},
};
use chattyness_error::AppError;

use crate::auth::{AuthUser, OptionalAuthUser, RlsConn};

/// Get user's full inventory.
///
/// GET /api/user/{uuid}/inventory
///
/// Supports "me" as a special UUID value to get the current user's inventory.
pub async fn get_user_inventory(
    rls_conn: RlsConn,
    AuthUser(user): AuthUser,
    Path(uuid_str): Path<String>,
) -> Result<Json<InventoryResponse>, AppError> {
    // Resolve "me" to current user ID, otherwise parse UUID
    let target_user_id = if uuid_str.eq_ignore_ascii_case("me") {
        user.id
    } else {
        uuid_str.parse::<Uuid>().map_err(|_| {
            AppError::Validation(format!("Invalid user UUID: {}", uuid_str))
        })?
    };

    // For now, users can only view their own inventory
    if target_user_id != user.id {
        return Err(AppError::Forbidden(
            "You can only view your own inventory".to_string(),
        ));
    }

    let mut conn = rls_conn.acquire().await;
    let items = inventory::list_user_inventory(&mut *conn, target_user_id).await?;

    Ok(Json(InventoryResponse { items }))
}

/// Drop an item from inventory.
///
/// DELETE /api/user/{uuid}/inventory/{item_id}
pub async fn drop_item(
    rls_conn: RlsConn,
    AuthUser(user): AuthUser,
    Path((uuid_str, item_id)): Path<(String, Uuid)>,
) -> Result<Json<serde_json::Value>, AppError> {
    // Resolve "me" to current user ID
    let target_user_id = if uuid_str.eq_ignore_ascii_case("me") {
        user.id
    } else {
        uuid_str.parse::<Uuid>().map_err(|_| {
            AppError::Validation(format!("Invalid user UUID: {}", uuid_str))
        })?
    };

    // Users can only drop from their own inventory
    if target_user_id != user.id {
        return Err(AppError::Forbidden(
            "You can only drop items from your own inventory".to_string(),
        ));
    }

    let mut conn = rls_conn.acquire().await;
    inventory::drop_inventory_item(&mut *conn, user.id, item_id).await?;

    Ok(Json(serde_json::json!({ "success": true })))
}

/// Get server prop catalog.
///
/// GET /api/server/inventory
///
/// Returns all public server props. If the user is authenticated (non-guest),
/// includes acquisition status (user_owns, is_claimed, is_available).
/// For guests/unauthenticated, returns default status values.
pub async fn get_server_props(
    State(pool): State<PgPool>,
    OptionalAuthUser(maybe_user): OptionalAuthUser,
) -> Result<Json<PropAcquisitionListResponse>, AppError> {
    // Get user_id if authenticated and not a guest
    let user_id = maybe_user
        .as_ref()
        .filter(|u: &&User| !u.is_guest())
        .map(|u| u.id);

    let props = inventory::list_server_props(&pool, user_id).await?;

    Ok(Json(PropAcquisitionListResponse { props }))
}

/// Get realm prop catalog.
///
/// GET /api/realms/{slug}/inventory
///
/// Returns all public realm props for the specified realm. If the user is authenticated
/// (non-guest), includes acquisition status. For guests/unauthenticated, returns default status.
pub async fn get_realm_props(
    State(pool): State<PgPool>,
    OptionalAuthUser(maybe_user): OptionalAuthUser,
    Path(slug): Path<String>,
) -> Result<Json<PropAcquisitionListResponse>, AppError> {
    // Get the realm by slug to get its ID
    let realm = realms::get_realm_by_slug(&pool, &slug)
        .await?
        .ok_or_else(|| AppError::NotFound(format!("Realm '{}' not found", slug)))?;

    // Get user_id if authenticated and not a guest
    let user_id = maybe_user
        .as_ref()
        .filter(|u: &&User| !u.is_guest())
        .map(|u| u.id);

    let props = inventory::list_realm_props(&pool, realm.id, user_id).await?;

    Ok(Json(PropAcquisitionListResponse { props }))
}

/// Acquire a server prop into user's inventory.
///
/// POST /api/server/inventory/request
pub async fn acquire_server_prop(
    rls_conn: RlsConn,
    AuthUser(user): AuthUser,
    Json(req): Json<AcquirePropRequest>,
) -> Result<Json<AcquirePropResponse>, AppError> {
    // Guests cannot acquire props
    if user.is_guest() {
        return Err(AppError::Forbidden(
            "Guests cannot acquire props".to_string(),
        ));
    }

    let mut conn = rls_conn.acquire().await;

    // Try to acquire the prop
    match inventory::acquire_server_prop(&mut *conn, req.prop_id, user.id).await {
        Ok(item) => Ok(Json(AcquirePropResponse { item })),
        Err(_) => {
            // Get the specific error reason
            let error =
                inventory::get_server_prop_acquisition_error(&mut *conn, req.prop_id, user.id)
                    .await?;
            Err(error)
        }
    }
}

/// Acquire a realm prop into user's inventory.
///
/// POST /api/realms/{slug}/inventory/request
pub async fn acquire_realm_prop(
    rls_conn: RlsConn,
    State(pool): State<PgPool>,
    AuthUser(user): AuthUser,
    Path(slug): Path<String>,
    Json(req): Json<AcquirePropRequest>,
) -> Result<Json<AcquirePropResponse>, AppError> {
    // Guests cannot acquire props
    if user.is_guest() {
        return Err(AppError::Forbidden(
            "Guests cannot acquire props".to_string(),
        ));
    }

    // Get the realm by slug to get its ID
    let realm = realms::get_realm_by_slug(&pool, &slug)
        .await?
        .ok_or_else(|| AppError::NotFound(format!("Realm '{}' not found", slug)))?;

    let mut conn = rls_conn.acquire().await;

    // Try to acquire the prop
    match inventory::acquire_realm_prop(&mut *conn, req.prop_id, realm.id, user.id).await {
        Ok(item) => Ok(Json(AcquirePropResponse { item })),
        Err(_) => {
            // Get the specific error reason
            let error = inventory::get_realm_prop_acquisition_error(
                &mut *conn,
                req.prop_id,
                realm.id,
                user.id,
            )
            .await?;
            Err(error)
        }
    }
}
