#![no_std]
#![no_main]

use esp_hal::{
    clock::ClockControl,
    peripherals::Peripherals,
    gpio::*,
    prelude::*,
    spi,
    timer::TimerGroup,
    Rtc,
    IO,
    Delay,
};

// Display and graphics imports
use mipidsi::options::{Orientation, ColorOrder};
use display_interface_spi::SPIInterfaceNoCS;
use embedded_graphics::{
    mono_font::MonoTextStyle,
    pixelcolor::*,
    prelude::*,
    primitives::*,
    text::*,
    image::Image,
    geometry::*,
    draw_target::DrawTarget,
};
use embedded_hal;
use profont::{PROFONT_24_POINT, PROFONT_18_POINT};
use esp_println::println;
use panic_halt as _; // Simple panic handler

// Display configuration constants
const DISPLAY_WIDTH: u16 = 240;
const DISPLAY_HEIGHT: u16 = 320;
const SPI_FREQUENCY: u32 = 100_000_000; // 100MHz

#[entry]
fn main() -> ! {
    // Initialize core peripherals
    let peripherals = Peripherals::take();
    let mut system = peripherals.SYSTEM.split();
    let mut clocks = ClockControl::boot_defaults(system.clock_control).freeze();

    // Configure watchdog timers
    let mut rtc = Rtc::new(peripherals.LPWR);
    let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
    let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
    
    let mut wdt0 = timer_group0.wdt;
    let mut wdt1 = timer_group1.wdt;
    
    // Disable watchdogs
    rtc.rwdt.disable();
    wdt0.disable();
    wdt1.disable();

    println!("Initializing display...");

    // GPIO initialization
    let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
    
    // Configure display pins
    let mosi = io.pins.gpio7;
    let cs = io.pins.gpio2;
    let rst = io.pins.gpio10;
    let dc = io.pins.gpio3;
    let sck = io.pins.gpio6;
    let miso = io.pins.gpio8;
    let backlight = io.pins.gpio4;

    // Configure backlight
    let mut backlight = backlight.into_push_pull_output();
    // backlight.set_low().unwrap(); // Uncomment to turn on backlight

    // SPI Configuration
    let spi = spi::master::Spi::new(
        peripherals.SPI2,
        SPI_FREQUENCY.MHz(),
        spi::SpiMode::Mode0,
        &mut clocks,
    ).with_pins(
        Some(sck),
        Some(mosi),
        Some(miso),
        Some(cs),
    );

    // Display interface configuration
    let di = SPIInterfaceNoCS::new(spi, dc.into_push_pull_output());
    let reset = rst.into_push_pull_output();
    let mut delay = Delay::new(&clocks);

    // Initialize display
    let mut display = mipidsi::Builder::ili9341_rgb565(di)
        .with_display_size(DISPLAY_WIDTH, DISPLAY_HEIGHT)
        .with_framebuffer_size(DISPLAY_WIDTH, DISPLAY_HEIGHT)
        .with_orientation(Orientation::LandscapeInverted(true))
        .with_color_order(ColorOrder::Bgr)
        .init(&mut delay, Some(reset))
        .unwrap();

    println!("Display initialized successfully");

    // Clear display and show initial message
    if let Err(e) = display.clear(Rgb565::WHITE) {
        println!("Failed to clear display: {:?}", e);
    }

    // Calculate text position for center alignment
    let text_position = display.bounding_box().center() 
        - Size::new(display.bounding_box().size.width/2 - 10, 0);

    // Draw welcome text
    Text::new(
        "Display Ready",
        text_position,
        MonoTextStyle::new(&PROFONT_24_POINT, Rgb565::RED)
    )
    .draw(&mut display)
    .unwrap();

    // Main loop
    loop {
        // Device is alive but idle
        delay.delay_ms(100u32);
    }
}