//! Server avatars management API handlers for admin UI.

use axum::Json;
use axum::extract::State;
use chattyness_db::{
    models::{CreateServerAvatarRequest, ServerAvatar, ServerAvatarSummary, UpdateServerAvatarRequest},
    queries::server_avatars,
};
use chattyness_error::AppError;
use serde::Serialize;
use sqlx::PgPool;
use uuid::Uuid;

use crate::auth::AdminConn;

// =============================================================================
// API Types
// =============================================================================

/// Response for avatar creation.
#[derive(Debug, Serialize)]
pub struct CreateAvatarResponse {
    pub id: Uuid,
    pub slug: String,
    pub name: String,
    pub is_public: bool,
    pub created_at: chrono::DateTime<chrono::Utc>,
}

impl From<ServerAvatar> for CreateAvatarResponse {
    fn from(avatar: ServerAvatar) -> Self {
        Self {
            id: avatar.id,
            slug: avatar.slug,
            name: avatar.name,
            is_public: avatar.is_public,
            created_at: avatar.created_at,
        }
    }
}

// =============================================================================
// API Handlers
// =============================================================================

/// List all server avatars.
pub async fn list_avatars(
    State(pool): State<PgPool>,
) -> Result<Json<Vec<ServerAvatarSummary>>, AppError> {
    let avatars = server_avatars::list_all_server_avatars(&pool).await?;
    Ok(Json(avatars))
}

/// Create a new server avatar.
pub async fn create_avatar(
    admin_conn: AdminConn,
    Json(req): Json<CreateServerAvatarRequest>,
) -> Result<Json<CreateAvatarResponse>, AppError> {
    let conn = admin_conn.0;
    let mut guard = conn.acquire().await;

    // Validate the request
    req.validate()?;

    // Check slug availability
    let slug = req.slug_or_generate();
    let available = server_avatars::is_avatar_slug_available(&mut *guard, &slug).await?;
    if !available {
        return Err(AppError::Conflict(format!(
            "Avatar slug '{}' is already taken",
            slug
        )));
    }

    // Create the avatar
    let avatar = server_avatars::create_server_avatar(&mut *guard, &req, None).await?;

    tracing::info!("Created server avatar: {} ({})", avatar.name, avatar.id);

    Ok(Json(CreateAvatarResponse::from(avatar)))
}

/// Get a server avatar by ID.
pub async fn get_avatar(
    State(pool): State<PgPool>,
    axum::extract::Path(avatar_id): axum::extract::Path<Uuid>,
) -> Result<Json<ServerAvatar>, AppError> {
    let avatar = server_avatars::get_server_avatar_by_id(&pool, avatar_id)
        .await?
        .ok_or_else(|| AppError::NotFound("Avatar not found".to_string()))?;
    Ok(Json(avatar))
}

/// Update a server avatar.
pub async fn update_avatar(
    admin_conn: AdminConn,
    axum::extract::Path(avatar_id): axum::extract::Path<Uuid>,
    Json(req): Json<UpdateServerAvatarRequest>,
) -> Result<Json<ServerAvatar>, AppError> {
    let conn = admin_conn.0;
    let mut guard = conn.acquire().await;

    // Validate the request
    req.validate()?;

    // Check avatar exists
    let existing = server_avatars::get_server_avatar_by_id(&mut *guard, avatar_id)
        .await?
        .ok_or_else(|| AppError::NotFound("Avatar not found".to_string()))?;

    // Update the avatar
    let avatar = server_avatars::update_server_avatar(&mut *guard, avatar_id, &req).await?;

    tracing::info!("Updated server avatar: {} ({})", existing.name, avatar_id);

    Ok(Json(avatar))
}

/// Delete a server avatar.
pub async fn delete_avatar(
    admin_conn: AdminConn,
    axum::extract::Path(avatar_id): axum::extract::Path<Uuid>,
) -> Result<Json<()>, AppError> {
    let conn = admin_conn.0;
    let mut guard = conn.acquire().await;

    // Get the avatar first to log its name
    let avatar = server_avatars::get_server_avatar_by_id(&mut *guard, avatar_id)
        .await?
        .ok_or_else(|| AppError::NotFound("Avatar not found".to_string()))?;

    // Delete from database
    server_avatars::delete_server_avatar(&mut *guard, avatar_id).await?;

    tracing::info!("Deleted server avatar: {} ({})", avatar.name, avatar_id);

    Ok(Json(()))
}
