use axum::{extract::Multipart, http::StatusCode, Json};
use serde::Serialize;
use uuid::Uuid;

use crate::middleware::auth::AuthUser;

/// Response returned after a chat image upload succeeds.
#[derive(Serialize)]
pub struct UploadResponse {
    pub url: String,
}

/// Accept a multipart chat image upload and store it under `uploads/chat-images`.
pub async fn upload_chat_image(
    _auth: AuthUser,
    mut multipart: Multipart,
) -> Result<Json<UploadResponse>, (StatusCode, String)> {
    while let Some(field) = multipart
        .next_field()
        .await
        .map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?
    {
        let content_type = field.content_type().unwrap_or("").to_string();
        let ext = match content_type.as_str() {
            "image/png" => "png",
            "image/jpeg" => "jpg",
            "image/gif" => "gif",
            "image/webp" => "webp",
            _ => {
                return Err((
                    StatusCode::BAD_REQUEST,
                    "Only PNG, JPG, GIF, WebP images are allowed".into(),
                ))
            }
        };

        let data = field
            .bytes()
            .await
            .map_err(|e| (StatusCode::BAD_REQUEST, e.to_string()))?;

        if data.len() > 5 * 1024 * 1024 {
            return Err((StatusCode::BAD_REQUEST, "Image must be under 5MB".into()));
        }

        let dir = "uploads/chat-images";
        tokio::fs::create_dir_all(dir)
            .await
            .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

        let filename = format!("{}.{}", Uuid::new_v4(), ext);
        let path = format!("{}/{}", dir, filename);

        tokio::fs::write(&path, &data)
            .await
            .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;

        return Ok(Json(UploadResponse {
            url: format!("/uploads/chat-images/{}", filename),
        }));
    }

    Err((StatusCode::BAD_REQUEST, "No image provided".into()))
}
