rizzoo 0.6.7

a cross platform color generation tool implementing Material 3 Expressive
use crate::error::LRatio;
use crate::paths::Paths;
use sha2::{Digest, Sha256};
use std::path::PathBuf;

pub fn download(url: &str) -> Result<PathBuf, LRatio> {
    let mut response = ureq::get(url)
        .call()
        .map_err(|e| LRatio::Custom(format!("failed to download image from URL: {e}")))?;

    let image_size = response
        .body_mut()
        .with_config()
        .limit(1024 * 1024 * 100)
        .read_to_vec()
        .map_err(|e| LRatio::Custom(format!("failed to read image data: {e}")))?;

    if image_size.is_empty() {
        return Err(LRatio::Custom("downloaded image is empty".into()));
    }

    let ext = guess_extension(&image_size);
    let hash = url_hash(url);
    let paths = Paths::resolve()?;
    let path = paths.downloads_dir.join(format!("{}{}", hash, ext));
    std::fs::write(&path, &image_size)
        .map_err(|e| LRatio::Custom(format!("failed to write image file: {e}")))?;
    Ok(path)
}

pub fn url_hash(url: &str) -> String {
    let mut hasher = Sha256::new();
    hasher.update(url.as_bytes());
    hasher
        .finalize()
        .iter()
        .map(|b| format!("{:02x}", b))
        .collect()
}

pub fn cached_url_path(url: &str, paths: &Paths) -> Option<PathBuf> {
    let hash = url_hash(url);
    for ext in [".png", ".jpg", ".jpeg", ".webp", ".gif", ".bmp"] {
        let p = paths.downloads_dir.join(format!("{}{}", hash, ext));
        if p.exists() {
            return Some(p);
        }
    }
    None
}

fn guess_extension(bytes: &[u8]) -> &'static str {
    if bytes.len() < 4 {
        return ".png";
    }
    match &bytes[..4] {
        [0x89, 0x50, 0x4E, 0x47] => ".png",
        [0xFF, 0xD8, 0xFF, _] => ".jpg",
        [0x52, 0x49, 0x46, 0x46] => ".webp",
        [0x47, 0x49, 0x46, _] => ".gif",
        [0x42, 0x4D, _, _] => ".bmp",
        _ => ".png",
    }
}