use bone_render::{ClearColor, PixelDiff, PixelDiffThreshold, Style, ViewportExtent, ViewportPx};

mod common;

use common::{extent_square as extent, make_context};

fn expected_rgba(extent: ViewportExtent, color: ClearColor) -> Vec<u8> {
    let pixel = color.to_rgba8();
    let count = usize::try_from(extent.pixel_count()).unwrap_or(0);
    (0..count).flat_map(|_| pixel.into_iter()).collect()
}

#[test]
fn offscreen_clear_matches_style_background_exactly() {
    let size = extent(64);
    let ctx = make_context(size);
    let style = Style::default();

    let Ok(frame) = ctx.render_clear(&style) else {
        panic!("render_clear failed");
    };

    assert_eq!(frame.extent(), size);
    let expected = expected_rgba(size, style.background());
    assert_eq!(frame.rgba().len(), expected.len());

    let Ok(report) = PixelDiff::compare(&frame, &expected, PixelDiffThreshold::EXACT) else {
        panic!("pixel diff rejected inputs");
    };
    assert!(
        report.is_clean(),
        "clear frame diverged from expected bytes: {} mismatches, worst {:?}",
        report.over_threshold(),
        report.worst(),
    );
}

#[test]
fn offscreen_clear_honours_custom_background() {
    let size = extent(32);
    let ctx = make_context(size);
    let background = ClearColor::opaque(0.25, 0.50, 0.75);
    let style = Style::new(background);

    let Ok(frame) = ctx.render_clear(&style) else {
        panic!("render_clear failed");
    };

    let expected = expected_rgba(size, background);
    let Ok(report) = PixelDiff::compare(&frame, &expected, PixelDiffThreshold::EXACT) else {
        panic!("pixel diff rejected inputs");
    };
    assert!(
        report.is_clean(),
        "custom clear diverged: {} mismatches",
        report.over_threshold(),
    );
}

#[test]
fn offscreen_extent_with_non_aligned_width_reads_back_packed_rgba() {
    let size = ViewportExtent::new(ViewportPx::new(63), ViewportPx::new(16));
    let ctx = make_context(size);
    let style = Style::new(ClearColor::opaque(1.0, 0.0, 0.0));

    let Ok(frame) = ctx.render_clear(&style) else {
        panic!("render_clear failed");
    };

    let expected = expected_rgba(size, style.background());
    assert_eq!(frame.rgba().len(), expected.len());
    let Ok(report) = PixelDiff::compare(&frame, &expected, PixelDiffThreshold::EXACT) else {
        panic!("pixel diff rejected inputs");
    };
    assert!(report.is_clean(), "unaligned width readback diverged");
}
