use esp_idf_hal::i2c::*;
use esp_idf_hal::prelude::*;
use esp_idf_hal::delay::FreeRtos;
use esp_idf_hal::peripherals::Peripherals;

use std::sync::{Arc, Mutex};

mod lcd;

const WIDTH: i32 = 20;
const FAKE_TIME: &str = "12:43";
const FAKE_DATE: &str = "Thu 8 Jun";

const DAY: i32 = 24 * 60;
const HOUR: i32 = 60;

#[derive(Debug, PartialEq)]
pub struct Clock {
    minutes: i32,
}

impl core::fmt::Display for Clock {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // Use `:02` for padding with zeros up to two places.
        write!(f, "{:0>2}:{:0>2}", self.minutes / HOUR, self.minutes % HOUR)
    }
}

impl Clock {
    pub fn new(hours: i32, minutes: i32) -> Self {
        Self {
            // Remove overlap of days.
            minutes: (hours * HOUR + minutes).rem_euclid(DAY),
        }
    }
    pub fn add_minutes(&self, minutes: i32) -> Self {
        // Create a new instance of self with extra minutes
        Self::new(0, self.minutes + minutes)
    }
}

pub struct Point {
    pub x: i32,
    pub y: i32,
}

impl Point {
    pub fn new(x: i32, y: i32) -> Self {
        Self {
            x,
            y,
        }
    }
}

pub fn draw_text(config: &mut I2cDriver, position: Point, text: &str, centered: bool) {
    let _ = match centered {
        true => lcd::set_cursor(config, get_centered(text.into()) as u8, position.y as usize),
        false => lcd::set_cursor(config, position.x as u8, position.y as usize),
    };

    let _ = lcd::print_str(config, text);
}

fn get_centered(text: String) -> i32 {
    let val = (20 - text.len()) / 2;

    dbg!(val);

    val.try_into().unwrap()
}

fn main() -> anyhow::Result<()> {
    let mut clock = Clock::new(10, 43);

    println!("{clock}");

    let peripherals = Peripherals::take().unwrap();
    let i2c = peripherals.i2c0;
    let sda = peripherals.pins.gpio6;
    let scl = peripherals.pins.gpio5;

    let config = I2cConfig::new().baudrate(100.kHz().into());
    let mut i2c = I2cDriver::new(i2c, sda, scl, &config)?;

    let _ = lcd::init(&mut i2c);
    let _ = lcd::backlight(&mut i2c);

    //draw_text(&mut i2c, Point::new(4, 1), "12:43", true);
    
    loop {
        draw_text(&mut i2c, Point::new(0, 1), &clock.to_string(), true);
        draw_text(&mut i2c, Point::new(0, 2), "Thu 8 June", true);

        FreeRtos::delay_ms(60000);

        clock = clock.add_minutes(1);
    }
}