use anyhow::Result;
use std::path::{Path, PathBuf};
use std::io::{Error, ErrorKind};
use walkdir::WalkDir;
use photon_rs::PhotonImage;
use std::fs;
use photon_rs::colour_spaces::{darken_hsl, lighten_hsl};
use photon_rs::transform::resize;
use photon_rs::transform::SamplingFilter::Lanczos3;
use photon_rs::native::{open_image, save_image};

static CONTENTS_JSON_BODY: &str = include_str!("../data/Contents.json");


pub fn run(icon_fpath: &str, output: &PathBuf, lighten_factor: f32, force: bool) -> Result<()> {
    let img = open_image(icon_fpath).expect(&format!("{}: Could not open file.", icon_fpath));
    let size = (img.get_width(), img.get_height());
    if size != (1024, 1024) {
        return Err(anyhow::anyhow!("{}: Image size must be 1024x1024", icon_fpath));
    }

    for (icon_set_dir, lighten) in vec![
        ("AppIcon.appiconset", 0.0),
        ("AppIconDev.appiconset", lighten_factor),
    ] {
        let p = output.join(icon_set_dir);
        if force {
            fs::remove_dir_all(&p);
        }
        let modified = if lighten == 0. {
            img.clone()
        } else if lighten > 0. {
            let mut t = img.clone();
            lighten_hsl(&mut t, lighten);
            t
        } else {
            let mut t = img.clone();
            darken_hsl(&mut t, -lighten);
            t
        };
        write_directory(&p, modified)?;
    }
    Ok(())
}


pub fn find_assets_dir() -> Result<PathBuf, Error> {
    for dir in WalkDir::new(".").into_iter().filter_map(|e| e.ok()) {
        if dir.path().file_name().unwrap_or("".as_ref()).to_str().unwrap() == "Assets.xcassets" {
            return Ok(dir.path().to_path_buf());
        }
    }
    return Err(Error::new(ErrorKind::NotFound, "Did not find Assets.xcassets."));
}

static SIZES: [u32; 19] = [
    1024,
    180,
    167,
    152,
    144,
    120,
    114,
    100,
    87,
    80,
    76,
    72,
    60,
    58,
    57,
    50,
    40,
    29,
    20,
];

pub fn write_directory(path: &PathBuf, img: PhotonImage) -> Result<(), Error> {
    fs::create_dir(path).expect(&format!("{}: Directory already exists.", path.display()));
    fs::write(path.join("Contents.json"), CONTENTS_JSON_BODY);
    for dim in SIZES {
        let resized = if dim == img.get_height() && dim == img.get_width() {
            img.clone()
        } else {
            resize(&img, dim, dim, Lanczos3)
        };
        save_image(resized, path.join(format!("{}.png", dim)).to_str().unwrap());
    }
    eprintln!("{}: Wrote icon set.", path.display());
    Ok(())
}
