use criterion::BenchmarkId;
use criterion::Throughput;
use criterion::{black_box, criterion_group, criterion_main, Criterion};

use image::imageops::FilterType;
use image::GenericImageView;

use photosync::library::load_image;
use photosync::library::resize;
use photosync::library::save_to_jpeg_bytes;

pub fn criterion_benchmark(c: &mut Criterion) {
    const TEST_IMAGE_PATH: &'static str = "testdata/image.jpg";
    let img = load_image(TEST_IMAGE_PATH).expect("failed to load test image");
    c.bench_function("Load image", |b| {
        b.iter(|| black_box(load_image(TEST_IMAGE_PATH)))
    });

    let mut group = c.benchmark_group("Resizing");
    for size in [
        (None, None),
        (Some(256), Some(256)),
        (Some(512), Some(512)),
        (Some(1024), Some(1024)),
        (Some(2048), Some(2048)),
    ]
    .iter()
    {
        let (w, h) = size;
        for filter in [
            FilterType::Nearest,
            FilterType::CatmullRom,
            FilterType::Lanczos3,
        ]
        .iter()
        {
            let (img_w, img_h) = img.dimensions();
            let pixels = (img_w * img_h) as u64;
            group.throughput(Throughput::Elements(pixels));
            group.bench_with_input(
                BenchmarkId::new(
                    format!("{:?}", filter),
                    format!(
                        "{}x{}",
                        w.map(|i| i.to_string()).unwrap_or("FULL".to_string()),
                        h.map(|i| i.to_string()).unwrap_or("FULL".to_string())
                    ),
                ),
                &(size, filter),
                |b, (size, &filter)| b.iter(|| black_box(resize(&img, **size, filter))),
            );
        }

        group.bench_with_input(
            BenchmarkId::new(
                "Save to bytes",
                format!(
                    "{}x{}",
                    w.map(|i| i.to_string()).unwrap_or("FULL".to_string()),
                    h.map(|i| i.to_string()).unwrap_or("FULL".to_string())
                ),
            ),
            size,
            |b, size| {
                let small_img = resize(&img, *size, FilterType::Lanczos3);
                b.iter(|| black_box(save_to_jpeg_bytes(&small_img)))
            },
        );

        group.bench_with_input(
            BenchmarkId::new(
                "Full pipeline Lanczos3",
                format!(
                    "{}x{}",
                    w.map(|i| i.to_string()).unwrap_or("FULL".to_string()),
                    h.map(|i| i.to_string()).unwrap_or("FULL".to_string())
                ),
            ),
            size,
            |b, size| {
                b.iter(|| {
                    let img = load_image(TEST_IMAGE_PATH).expect("failed to load test image");
                    let small_img = resize(&img, *size, FilterType::Lanczos3);
                    black_box(save_to_jpeg_bytes(&small_img))
                })
            },
        );
    }
    group.finish();
}

criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
