use image::{GenericImageView, ImageReader, Rgba};

const TOAST_TIME_SECONDS: u64 = 10;
const CENTER_X: f64 = 100.0;
const CENTER_Y: f64 = 100.0;
const BREAD_HEIGHT: f64 = 0.3;
const IDLE_HEIGHT: f64 = BREAD_HEIGHT + 8.0;
const PIXEL_SIZE_MM: f64 = 1.5;

fn main() -> anyhow::Result<()> {
    let img = ImageReader::open("/home/stephen/Downloads/scd31-qr.png")?.decode()?;

    preamble();

    // 2x oversampling
    for x in 0..(img.width() * 2 - 1) {
        for y in 0..(img.height() * 2 - 1) {
            let black = is_black(img.get_pixel(x / 2, y / 2))
                && is_black(img.get_pixel(x / 2 + x % 2, y / 2))
                && is_black(img.get_pixel(x / 2, y / 2 + y % 2))
                && is_black(img.get_pixel(x / 2 + x % 2, y / 2 + y % 2));

            if black {
                toast(
                    x as f64 - (img.width() as f64 / 2.0),
                    y as f64 + (img.height() as f64 / 2.0), // correct for reflection when printing
                );
            }
        }
    }

    Ok(())
}

fn is_black(p: Rgba<u8>) -> bool {
    match p.0 {
        [0, 0, 0, 255] => true,
        [255, 255, 255, 255] => false,
        _ => panic!("Pixel was not entirely black nor entirely white: {:?}", p),
    }
}

fn preamble() {
    println!(
        r#"
G28 ; home
G90 ; absolute positioning
G0 Z{IDLE_HEIGHT}
G0 X{CENTER_X} Y{CENTER_Y}
M109 S260 ; heat hotend and wait
"#
    );
}

fn toast(x: f64, y: f64) {
    println!(
        r#"
G0 X{:.2} Y{:.2};
G0 Z{BREAD_HEIGHT};
G4 S{TOAST_TIME_SECONDS} ; wait
G0 Z{IDLE_HEIGHT};
"#,
        x * PIXEL_SIZE_MM + CENTER_X,
        y * PIXEL_SIZE_MM + CENTER_Y
    );
}