use crate::serial;
use crate::serial::SioControl;
use core::fmt::Write;
use gba::prelude::*;
use gba_utils::gfx;
use heapless::Vec;
use voladdress::{Safe, VolAddress};

static WRITER: Mutex<Option<gfx::GfxWriter<gfx::Subpixel4x8>>> = Mutex::new(None);
static STATES: Mutex<Vec<u16, 64>> = Mutex::new(Vec::new());

pub const SIOCNT_: VolAddress<SioControl, Safe, Safe> = unsafe { VolAddress::new(0x400_0128) };

pub fn init() -> ! {
    {
        let mut opt_writer = WRITER.lock();
        let di = gfx::text_mode_setup(true);
        opt_writer.replace(gfx::GfxWriter::new(0, 0, di));
    }

    const FLAGS: InterruptFlags = InterruptFlags::new().with_serial(true).with_timer0(true);

    const TCTRL: TimerControl = TimerControl::new()
        .with_prescaler_selection(3)
        .with_irq_on_overflow(true)
        .with_enabled(true);

    TIMER0_RELOAD.write(0);
    TIMER0_CONTROL.write(TCTRL);

    serial::init(true);

    unsafe {
        IE.write(FLAGS);
        IME.write(true);
    }

    let write_data = "the quick brown fox jumps over the lazy dog\n";

    serial::write(write_data.as_bytes());

    loop {
        unsafe {
            Halt();
        };
    }
}

pub fn timer_irq() {
    let v = STATES.lock();
    let mut lock = WRITER.lock();
    let writer = lock.as_mut().unwrap();

    write!(writer, "{} items: ", v.len()).ok();
    for state in v.iter() {
        write!(writer, "{} ", (state >> 4) & 7).ok();
    }
    write!(writer, "\n").ok();
}

pub fn serial_irq(state: u16) {
    STATES.lock().push(state).ok();
    //
    // writeln!(writer, "TX FL: {} RX EM: {} ERR: {}", state.tx_full(), state.rx_empty(), state.error());
}
