use std::{
    fs,
    path::{Path, PathBuf},
};

use image::{ImageFormat, imageops::FilterType};
use rocket::{
    form::Form,
    fs::{NamedFile, TempFile},
    http::Status,
    serde::json::Json,
};

use serde::Serialize;
use tokio::io::AsyncReadExt;

pub fn routes() -> Vec<rocket::Route> {
    routes![profile_pic, general]
}

#[get("/profile/<user_id>")]
pub async fn profile_pic(user_id: usize) -> Option<NamedFile> {
    if let Ok(image) =
        NamedFile::open(Path::new("./cdn/profiles/full/").join(format!("{}.jpg", user_id))).await
    {
        Some(image)
    } else {
        Some(
            NamedFile::open("../../cdn/profiles/full/default.svg")
                .await
                .ok()?,
        )
    }
}

#[get("/<file_name..>")]
pub async fn general(file_name: PathBuf) -> Option<NamedFile> {
    NamedFile::open(Path::new("./cdn/").join(file_name))
        .await
        .ok()
}

#[derive(Serialize)]
pub struct UploadResponse {
    success: bool,
    message: String,
    url: Option<String>,
}
// Upload endpoint - handles image upload and creates multiple sizes
#[post("/profile/<user_id>/upload", data = "<file>")]
pub async fn upload_profile_pic(
    user_id: usize,
    file: Form<TempFile<'_>>,
) -> Result<Json<UploadResponse>, Status> {
    const MAX_FILE_SIZE: u64 = 5 * 1024 * 1024;
    if file.len() > MAX_FILE_SIZE {
        return Ok(Json(UploadResponse {
            success: false,
            message: "File size exceeds 5MB limit".to_string(),
            url: None,
        }));
    }

    // Read file contents into buffer
    let mut buffer = Vec::new();
    file.open()
        .await
        .map_err(|e| {
            eprintln!("Failed to open file: {}", e);
            Status::BadRequest
        })?
        .read_to_end(&mut buffer)
        .await
        .map_err(|e| {
            eprintln!("Failed to read file: {}", e);
            Status::BadRequest
        })?;

    // Check if buffer is empty
    if buffer.is_empty() {
        return Ok(Json(UploadResponse {
            success: false,
            message: "Uploaded file is empty".to_string(),
            url: None,
        }));
    }

    // Validate format from buffer
    let format = image::guess_format(&buffer).map_err(|e| {
        eprintln!("Failed to guess format: {}", e);
        Status::BadRequest
    })?;

    // Only allow specific image formats
    let allowed_formats = [
        ImageFormat::Jpeg,
        ImageFormat::Png,
        ImageFormat::WebP,
        ImageFormat::Gif,
    ];

    if !allowed_formats.contains(&format) {
        return Ok(Json(UploadResponse {
            success: false,
            message: "Unsupported image format. Only JPEG, PNG, WebP, and GIF are allowed."
                .to_string(),
            url: None,
        }));
    }

    // Decode and validate the image before persisting anything
    let img = image::load_from_memory(&buffer).map_err(|e| {
        eprintln!("Image decode error: {}", e);
        Status::BadRequest
    })?;

    // Now that we know it's valid, ensure directories exist
    let base_path = Path::new("./cdn/profiles");
    fs::create_dir_all(base_path.join("thumb")).map_err(|_| Status::InternalServerError)?;
    fs::create_dir_all(base_path.join("full")).map_err(|_| Status::InternalServerError)?;

    // Create thumbnail (64x64) for chat lists
    let thumb = img.resize_to_fill(64, 64, FilterType::Lanczos3);
    let thumb_path = base_path.join("thumb").join(format!("{}.jpg", user_id));
    thumb
        .save_with_format(&thumb_path, ImageFormat::Jpeg)
        .map_err(|_| Status::InternalServerError)?;

    // Create full size (256x256) for profile views
    let full = img.resize_to_fill(256, 256, FilterType::Lanczos3);
    let full_path = base_path.join("full").join(format!("{}.jpg", user_id));
    full.save_with_format(&full_path, ImageFormat::Jpeg)
        .map_err(|_| Status::InternalServerError)?;

    Ok(Json(UploadResponse {
        success: true,
        message: "Profile picture uploaded successfully".to_string(),
        url: Some(format!("/cdn/profile/{}", user_id)),
    }))
}
