use std::path::PathBuf;

use bone_render::{
    Camera2, PixelDiff, PixelDiffThreshold, SketchRenderer, SketchScene, Style, decode_png,
    encode_png,
};

mod common;

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

const GOLDEN: &str = "tests/goldens/grid_empty_256.png";
const UPDATE_ENV: &str = "BONE_UPDATE_GRID_GOLDEN";
const DIFF_TOLERANCE: f64 = 16.0 / 255.0;

fn golden_path() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(GOLDEN)
}

#[test]
fn grid_empty_sketch_matches_golden() {
    let size = extent(256);
    let ctx = make_context(size);
    let mut renderer = SketchRenderer::new(ctx.gpu(), ctx.color_format());
    let scene = SketchScene::empty();
    let camera = Camera2::new(size);
    let style = Style::default();

    let Ok(frame) = renderer.render(&ctx, &scene, camera, &style) else {
        panic!("SketchRenderer::render failed");
    };

    let path = golden_path();

    if std::env::var(UPDATE_ENV).is_ok() {
        let Ok(bytes) = encode_png(&frame) else {
            panic!("encode_png failed");
        };
        if let Some(parent) = path.parent() {
            assert!(
                std::fs::create_dir_all(parent).is_ok(),
                "failed to create goldens dir"
            );
        }
        assert!(
            std::fs::write(&path, &bytes).is_ok(),
            "failed to write golden {}",
            path.display()
        );
        return;
    }

    let Ok(bytes) = std::fs::read(&path) else {
        panic!(
            "golden missing at {}: rerun with {UPDATE_ENV}=1 to generate",
            path.display()
        );
    };
    let Ok((golden_extent, golden_rgba)) = decode_png(&bytes) else {
        panic!("failed to decode golden PNG");
    };
    assert_eq!(golden_extent, size, "golden extent drift");
    let threshold = PixelDiffThreshold::new(DIFF_TOLERANCE);
    let Ok(report) = PixelDiff::compare(&frame, &golden_rgba, threshold) else {
        panic!("PixelDiff rejected inputs");
    };
    assert!(
        report.is_clean(),
        "grid render drifted from golden: {} mismatches, worst {:?}, backend {}",
        report.over_threshold(),
        report.worst(),
        frame.backend(),
    );
}
