use core::periph::at28c256::At28C256;
use core::computers::rom_only::RomOnlyComputer;
use macroquad::prelude::*;
use core::traits::backplane::Backplane;

#[macroquad::main("RomOnlyComputer GUI")]
async fn main() {
    let mut computer = RomOnlyComputer {
        rom: At28C256::new(0x0000, 0x3fff, [0xea; 0x4000].to_vec()),
        data_bus: 0x00,
        address_bus: 0x0000,
        read_mode: true,
    };

    let mut input_addr = String::new();
    let mut input_data = String::new();

    loop {
        clear_background(GRAY);
        let mut y = 20.0;

        draw_text("RomOnlyComputer", 20.0, y, 30.0, WHITE);
        y += 40.0;

        // Address input
        draw_text("Address Bus (hex):", 20.0, y, 24.0, WHITE);
        y += 30.0;
        draw_input_box(&mut input_addr, 20.0, y, 100.0, 30.0);
        y += 40.0;

        // Data input
        draw_text("Data Bus (hex):", 20.0, y, 24.0, WHITE);
        y += 30.0;
        draw_input_box(&mut input_data, 20.0, y, 100.0, 30.0);
        y += 40.0;

        // Read mode checkbox
        let read_mode_rect = Rect::new(20.0, y, 20.0, 20.0);
        draw_rectangle_lines(read_mode_rect.x, read_mode_rect.y, read_mode_rect.w, read_mode_rect.h, 2.0, WHITE);
        if computer.read_mode() {
            draw_text("✔", read_mode_rect.x + 2.0, read_mode_rect.y + 18.0, 20.0, GREEN);
        }
        draw_text("Read Mode", read_mode_rect.x + 30.0, read_mode_rect.y + 18.0, 20.0, WHITE);
        if is_mouse_button_pressed(MouseButton::Left) && read_mode_rect.contains(mouse_position().into()) {
            computer.set_read_mode(!computer.read_mode());
        }
        y += 40.0;

        // Tick button
        let button_rect = Rect::new(20.0, y, 100.0, 40.0);
        draw_rectangle(button_rect.x, button_rect.y, button_rect.w, button_rect.h, DARKGRAY);
        draw_text("Tick", button_rect.x + 25.0, button_rect.y + 28.0, 24.0, WHITE);
        if is_mouse_button_pressed(MouseButton::Left) && button_rect.contains(mouse_position().into()) {
            if let (Ok(addr), Ok(data)) = (
                u16::from_str_radix(&input_addr.trim_start_matches("0x"), 16),
                u8::from_str_radix(&input_data.trim_start_matches("0x"), 16),
            ) {
                computer.set_address_bus(addr);
                computer.set_data_bus(data);
                // let result = computer.rom.tick(addr, data, computer.read_mode);
                println!(
                    "Tick: A=${:04X} D=${:02X} R={} -> ", // ${:02X}",
                    addr, data, computer.read_mode, // result
                );
            }
        }

        next_frame().await;
    }
}

fn draw_input_box(value: &mut String, x: f32, y: f32, w: f32, h: f32) {
    draw_rectangle(x, y, w, h, DARKGRAY);
    let mut display = value.clone();
    if get_time() as u64 % 2 == 0 {
        display.push('_');
    }
    draw_text(&display, x + 5.0, y + 22.0, 20.0, WHITE);

    let rect = Rect::new(x, y, w, h);
    if is_mouse_button_pressed(MouseButton::Left) && rect.contains(mouse_position().into()) {
        if let Some(chr) = get_char_pressed() {
            if chr.is_ascii_hexdigit() && value.len() < 4 {
                value.push(chr.to_ascii_uppercase());
            }
        }
        if is_key_pressed(KeyCode::Backspace) {
            value.pop();
        }
    }
}
