use embedded_graphics::mono_font::ascii::FONT_6X10;
use embedded_graphics::mono_font::MonoTextStyleBuilder;
use esp_hal::gpio::interconnect::PeripheralOutput;
use esp_hal::peripheral::Peripheral;
use esp_println::println;

use embedded_graphics::mono_font::MonoTextStyle;
use embedded_graphics::pixelcolor::BinaryColor;
use embedded_graphics::prelude::Point;
use embedded_graphics::text::Baseline;
use embedded_graphics::text::Text;
use embedded_graphics::Drawable;
use esp_hal::i2c::master::I2c;
use esp_hal::Blocking;
use ssd1306::mode::BufferedGraphicsMode;
use ssd1306::mode::DisplayConfig;
use ssd1306::prelude::DisplayRotation;
use ssd1306::prelude::I2CInterface;
use ssd1306::size::DisplaySize128x64;
use ssd1306::I2CDisplayInterface;
use ssd1306::Ssd1306;

#[derive(Debug)]
pub enum DisplayError {
    InitializationError,
    CommunicationError,
}

pub struct Display<'a> {
    display: Ssd1306<
        I2CInterface<I2c<'a, Blocking>>,
        DisplaySize128x64,
        BufferedGraphicsMode<DisplaySize128x64>,
    >,
    text_style: MonoTextStyle<'static, BinaryColor>,
}

impl<'a> Display<'a> {
    /// Initialize the display with the given I2C pins
    pub fn new(
        i2c: impl Peripheral<P = impl esp_hal::i2c::master::Instance> + 'a,
        scl: impl Peripheral<P = impl PeripheralOutput> + 'a,
        sda: impl Peripheral<P = impl PeripheralOutput> + 'a,
    ) -> Result<Display<'a>, DisplayError> {
        
        let i2c = I2c::new(i2c, esp_hal::i2c::master::Config::default())
            .unwrap()
            .with_scl(scl)
            .with_sda(sda);

        // let i2c = i2c.with_scl(scl.clone()).with_sda(sda.clone());
        let interface = I2CDisplayInterface::new(i2c);

        let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
            .into_buffered_graphics_mode();

        display.init().unwrap();

        // Create the text style
        let text_style = MonoTextStyleBuilder::new()
            .font(&FONT_6X10)
            .text_color(BinaryColor::On)
            .build();

        Ok(Display {
            display,
            text_style,
        })
    }

    pub fn clear(&mut self) {
        // Clear the display
        self.display.clear_buffer();
        self.display.flush().unwrap();
    }
    /// Write text to the display
    pub fn write_text(&mut self, line: i32, text: &str) {
        println!("{}", text);

        Text::with_baseline(
            text,
            Point::new(0, line * 16),
            self.text_style,
            Baseline::Top,
        )
        .draw(&mut self.display)
        .unwrap();

        self.display.flush().unwrap();
    }
}
