use esp_idf_sys as _; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported
use esp_idf_hal::gpio::*;
//use esp_idf_hal::peripheral::*; //{Interrupt,Peripherals};
use esp_idf_hal::peripherals::*;
use esp_idf_hal::delay::Ets; 
use heapless::spsc::Queue;
use esp_idf_hal::timer::{TimerDriver,TimerConfig};
//use esp_idf_hal::timer::config::Config;
use core::cell::RefCell;
use esp_idf_hal::interrupt::{self};
use std::sync::{Mutex};
use std::ops::DerefMut;

struct PinEvent {
  state: bool,
  ev_time: u64,
}

static mut queue: Queue<PinEvent, 235> = Queue::new();
static MY_BTN: Mutex<RefCell<Option<PinDriver<Gpio25,Input>>>>  =
    Mutex::new(RefCell::new(None));
static MY_TMR: Mutex<RefCell<Option<TimerDriver>>> =
    Mutex::new(RefCell::new(None));
//How to adapt connecting interrupt based on https://wokwi.com/projects/333374799393849940 ?
unsafe fn wz_intr() {
    let (mut producer, mut consumer) = queue.split() ;
    interrupt::free(|| {
    let my_btn = MY_BTN.lock().unwrap();
    let my_tmr = MY_TMR.lock().unwrap();
    let mut state : bool = false;
    let mut ev_time : u64 = 0;
    if let Some(ref mut btn) = (*my_btn).borrow_mut().deref_mut() {
      state = btn.is_high();
    };
    if let Some(ref mut tim) = (*my_tmr).borrow_mut().deref_mut() {
      ev_time = tim.counter().unwrap();
    };
    let dta = PinEvent {
      state: state,
      ev_time: ev_time,
    };
    producer.enqueue(dta);
    })
}

fn main() {
    esp_idf_sys::link_patches();
    #[allow(unused)]
    let config = TimerConfig {
        divider : 2,
        //xtal : true,
        auto_reload : true,
      };
    #[allow(unused)]
    let peripherals = Peripherals::take().unwrap() ;
    let tim10 = peripherals.timer00;
    #[allow(unused)]
    let mut tmdr = TimerDriver::new(tim10,&config).unwrap();
    tmdr.enable(true);
    interrupt::free(|| MY_TMR.lock().unwrap().replace(Some(tmdr)));
    let button = peripherals.pins.gpio25;
    let mut but = PinDriver::input(button).unwrap();
    but.set_interrupt_type(InterruptType::AnyEdge).unwrap();
    unsafe {
      but.subscribe(|| {wz_intr()});
    }
    interrupt::free(|| MY_BTN.lock().unwrap().replace(Some(but)));
    /*interrupt::free(|| {
      let my_btn = MY_BTN.lock().unwrap();
      if let Some(ref mut xbtn) = (*my_btn).borrow_mut().deref_mut() {
        unsafe {
          xbtn.subscribe(||{ wz_intr()});
        };
      }; 
    });*/
    println!("Hello world!");
    loop {
        Ets::delay_ms(300);
        unsafe {
          let (mut producer, mut consumer) = queue.split();          
          println!("Report");
           while !queue.is_empty() {
            let dta = consumer.dequeue().unwrap();
            println!("state:{}, time:{}",dta.state, dta.ev_time);
          }
        }
    }
}