//! Capture the exact command sequence mipidsi's ST7796 model emits for our Builder config,
//! on the host — so we can diff it against the known-good CircuitPython st7796_init and stop
//! guessing at the panel bring-up. `cargo run --bin initdump`.

use core::convert::Infallible;
use embedded_graphics::{pixelcolor::Rgb565, prelude::*, primitives::{PrimitiveStyle, Rectangle}};
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{ErrorType, OutputPin};
use mipidsi::interface::Interface;
use mipidsi::models::ST7796;
use mipidsi::options::{ColorInversion, ColorOrder, Orientation};
use mipidsi::Builder;

/// Records every command + args mipidsi sends.
#[derive(Default)]
struct Rec {
    log: Vec<(u8, Vec<u8>)>,
}
impl Interface for Rec {
    type Word = u8;
    type Error = Infallible;
    fn send_command(&mut self, command: u8, args: &[u8]) -> Result<(), Infallible> {
        self.log.push((command, args.to_vec()));
        Ok(())
    }
    fn send_pixels<const N: usize>(
        &mut self,
        _pixels: impl IntoIterator<Item = [u8; N]>,
    ) -> Result<(), Infallible> {
        Ok(())
    }
    fn send_repeated_pixel<const N: usize>(
        &mut self,
        _pixel: [u8; N],
        _count: u32,
    ) -> Result<(), Infallible> {
        Ok(())
    }
}

struct NoPin;
impl ErrorType for NoPin {
    type Error = Infallible;
}
impl OutputPin for NoPin {
    fn set_low(&mut self) -> Result<(), Infallible> {
        Ok(())
    }
    fn set_high(&mut self) -> Result<(), Infallible> {
        Ok(())
    }
}

struct NoDelay;
impl DelayNs for NoDelay {
    fn delay_ns(&mut self, _ns: u32) {}
}

fn main() {
    let mut delay = NoDelay;
    let mut display = Builder::new(ST7796, Rec::default())
        .reset_pin(NoPin)
        .display_size(320, 480)
        .color_order(ColorOrder::Bgr)
        .invert_colors(ColorInversion::Inverted)
        .orientation(Orientation::new().flip_horizontal())
        .init(&mut delay)
        .unwrap();

    // boundary between init and draw commands (raw access to the recording interface)
    let init_len = unsafe { display.dcs() }.log.len();

    // Full-screen fill, then a single pixel at the far corner → reveals the address window.
    Rectangle::new(Point::new(0, 0), Size::new(320, 480))
        .into_styled(PrimitiveStyle::with_fill(Rgb565::BLUE))
        .draw(&mut display)
        .unwrap();
    Pixel(Point::new(319, 479), Rgb565::RED).draw(&mut display).unwrap();

    let (rec, _model, _rst) = display.release();

    println!("init: {init_len} commands; full log {} commands", rec.log.len());
    for (i, (c, a)) in rec.log.iter().enumerate() {
        let args = a.iter().map(|b| format!("{b:02X}")).collect::<Vec<_>>().join(" ");
        let tag = match c {
            0x2A => " <- CASET (col x0..x1)",
            0x2B => " <- RASET (row y0..y1)",
            0x2C => " <- RAMWR",
            _ => "",
        };
        let phase = if i < init_len { "init" } else { "draw" };
        println!("  [{phase}] 0x{c:02X}  {args}{tag}");
    }
}
