use std::alloc::System;
use std::hint::black_box;
use std::time::Instant;

use libremetaverse_imaging::{ManagedImage, ManagedImageImageChannels};
use stats_alloc::{INSTRUMENTED_SYSTEM, Region, StatsAlloc};

#[global_allocator]
static ALLOCATOR: &StatsAlloc<System> = &INSTRUMENTED_SYSTEM;

fn main() {
    const INPUT_SIDE: i32 = 2_048;
    const OUTPUT_SIDE: i32 = 1_024;

    let channels = ManagedImageImageChannels(
        ManagedImageImageChannels::COLOR.0 | ManagedImageImageChannels::ALPHA.0,
    );
    let mut source = ManagedImage::new(INPUT_SIDE, INPUT_SIDE, channels)
        .expect("large benchmark image must fit the documented pixel bound");
    for (index, red) in source.red.iter_mut().enumerate() {
        *red = u8::try_from(index & 0xff).expect("masked sample");
    }
    source.green.fill(97);
    source.blue.fill(193);
    source.alpha.fill(255);

    // Warm the validation path before measuring the owned clone, resize, and export pipeline.
    source.validate().expect("valid benchmark image");
    let allocation_region = Region::new(ALLOCATOR);
    let started = Instant::now();
    let mut resized = source.clone().expect("bounded image clone");
    resized
        .resize_bilinear(OUTPUT_SIDE, OUTPUT_SIDE)
        .expect("bounded bilinear resize");
    let rgba = resized.export_raw().expect("bounded RGBA export");
    let elapsed = started.elapsed();
    let allocation_stats = allocation_region.change();

    assert_eq!((resized.width, resized.height), (OUTPUT_SIDE, OUTPUT_SIDE));
    assert_eq!(rgba.len(), 4 * OUTPUT_SIDE as usize * OUTPUT_SIDE as usize);
    black_box((resized, rgba));
    println!(
        "image pipeline: {INPUT_SIDE}x{INPUT_SIDE} -> {OUTPUT_SIDE}x{OUTPUT_SIDE} in {elapsed:?}, {} allocations, {} reallocations, {} bytes allocated",
        allocation_stats.allocations,
        allocation_stats.reallocations,
        allocation_stats.bytes_allocated,
    );
}
