#[derive(Debug, PartialEq)]
enum ImageType {
    Jpeg,
    Png,
    Gif,
    WebP,
    AnimatedWebP,
    Unsupported,
}

/// function to interface with the tauri api on the javascript side
#[tauri::command]
pub fn process_wallpaper_image(file_path_string: String) -> Result<String, String> {
    // convert the string to a path
    let file_path = std::path::Path::new(&file_path_string);

    // determine the image type and get the file extension
    let file_extension = match determine_image_type(file_path) {
        Ok(image_type) => match image_type {
            ImageType::Jpeg => "jpeg".to_string(),
            ImageType::Png => "png".to_string(),
            ImageType::Gif => "gif".to_string(),
            ImageType::WebP => "webp".to_string(),
            ImageType::AnimatedWebP => "webp".to_string(),
            ImageType::Unsupported => {
                return Err("Unsupported image type (accepts webp, jpg, jpeg, png, gif)".to_string())
            }
        },
        Err(e) => return Err(format!("Error determining image type: {e}")),
    };

    let app_data_dir = crate::paths::get_app_data_dir()
        .map_err(|e| format!("Failed to get app data directory: {e}"))?;

    // construct the destination path
    let destination_path = app_data_dir.join(format!("wallpaper.{}", file_extension));

    // move the file to the destination
    crate::fs::copy_file(file_path, &destination_path, true)
        .map_err(|e| format!("Failed to move file: {e}"))?;

    Ok(destination_path.to_string_lossy().to_string())
}

#[tauri::command]
pub fn delete_old_wallpaper_image(file_path_string: String) -> Result<(), String> {
    // convert the strings to paths
    let file_path: &std::path::Path = std::path::Path::new(&file_path_string);

    // delete the old wallpaper
    crate::fs::delete_file(file_path).map_err(|e| format!("Failed to delete file: {e}"))?;

    Ok(())
}

/// determines the image type of a file that is passed in using the filepath
fn determine_image_type(file_path: &std::path::Path) -> Result<ImageType, String> {
    // open the file
    let mut file =
        std::fs::File::open(file_path).map_err(|e| format!("Failed to open file: {e}"))?;

    // read the first few bytes to determine the format
    let mut buffer = [0; 12];
    std::io::Read::read_exact(&mut file, &mut buffer)
        .map_err(|e| format!("Failed to read file: {e}"))?;

    // with hopes and prayers, try to guess the format and pray that it is correct haha
    match image::guess_format(&buffer) {
        Ok(image::ImageFormat::Jpeg) => Ok(ImageType::Jpeg),
        Ok(image::ImageFormat::Png) => Ok(ImageType::Png),
        Ok(image::ImageFormat::Gif) => Ok(ImageType::Gif),
        Ok(image::ImageFormat::WebP) => {
            // additional check for webp
            is_animated_webp(file_path).map(|animated| {
                if animated {
                    ImageType::AnimatedWebP
                } else {
                    ImageType::WebP
                }
            })
        }
        _ => Ok(ImageType::Unsupported),
    }
}

/// check if the file is a valid webp image and if it is animated
/// returns `Ok(true)` if it is animated, `Ok(false)` if it is not
/// and errors out if the file cannot be read or is not a webp
fn is_animated_webp(file_path: &std::path::Path) -> Result<bool, String> {
    // open the file and read its contents into a buffer
    let mut buffer = Vec::new();
    std::fs::File::open(file_path)
        .and_then(|mut file| std::io::Read::read_to_end(&mut file, &mut buffer))
        .map_err(|e| format!("Failed to read file: {}", e))?;

    // use the webp crate to decode the image and check for animation
    webp::AnimDecoder::new(&buffer)
        .decode()
        .map(|anim| anim.has_animation())
        .map_err(|_| "File is not a valid WebP image".to_string())
}
