use actix_multipart::Multipart;
use actix_web::{HttpResponse, Result, web};
use futures_util::StreamExt;
use service::AppService;
use session::Session;

#[derive(serde::Serialize, utoipa::ToSchema)]
pub struct AvatarUploadResponse {
    pub avatar_url: String,
}

/// Upload current user's avatar.
/// Accepts a multipart form with a single file field.
#[utoipa::path(
    post,
    path = "/api/users/me/avatar",
    responses(
        (status = 200, description = "Avatar uploaded", body = crate::ApiResponse<AvatarUploadResponse>),
        (status = 401, description = "Unauthorized"),
    ),
    tag = "User"
)]
pub async fn upload_avatar(
    service: web::Data<AppService>,
    session: Session,
    mut payload: Multipart,
) -> Result<HttpResponse, crate::error::ApiError> {
    let max_size: usize = 2 * 1024 * 1024; // 2MB

    let mut file_data: Vec<u8> = Vec::new();
    let mut file_ext = "png".to_string();

    while let Some(item) = payload.next().await {
        let mut field = item.map_err(|e| {
            crate::error::ApiError(service::error::AppError::BadRequest(e.to_string()))
        })?;

        // Detect file extension from content-type
        if let Some(content_type) = field.content_type() {
            let ext = match content_type.essence_str() {
                "image/jpeg" | "image/jpg" => "jpg",
                "image/gif" => "gif",
                "image/webp" => "webp",
                "image/png" | _ => "png",
            };
            file_ext = ext.to_string();
        }

        while let Some(chunk) = field.next().await {
            let data = chunk.map_err(|e| {
                crate::error::ApiError(service::error::AppError::BadRequest(e.to_string()))
            })?;
            if file_data.len() + data.len() > max_size {
                return Err(crate::error::ApiError(
                    service::error::AppError::BadRequest(
                        "File exceeds maximum size of 2MB".to_string(),
                    ),
                ));
            }
            file_data.extend_from_slice(&data);
        }
    }

    if file_data.is_empty() {
        return Err(crate::error::ApiError(
            service::error::AppError::BadRequest("No file provided".to_string()),
        ));
    }

    let avatar_url = service
        .user_avatar_upload(session, file_data, &file_ext)
        .await
        .map_err(crate::error::ApiError::from)?;

    Ok(crate::ApiResponse::ok(AvatarUploadResponse { avatar_url }).to_response())
}
