mod support;
use std::{sync::Arc, time::Instant};
use anyhow::Context;
use egui::TextBuffer;
use egui_glow::glow::{HasContext, COLOR_BUFFER_BIT};
use egui_sdl2_platform::sdl2;
use sdl2::event::{Event, WindowEvent};
use gemma::chip8::computer::Chip8Computer;
use support::timestep::TimeStep;
use crate::support::gemma_egui_support::GemmaEguiSupport;

const SCREEN_WIDTH: u32 = 800;
const SCREEN_HEIGHT: u32 = 480;

async fn run() -> anyhow::Result<String> {
    // Initialize SDL2 and video subsystem
    let sdl = sdl2::init().map_err(|e| anyhow::anyhow!("Failed to create SDL context: {}", e))?;
    let mut video = sdl.video().map_err(|e| anyhow::anyhow!("Failed to initialize SDL video subsystem: {}", e))?;


    // Create SDL2 window and OpenGL context
    let window = video.window("Window", SCREEN_WIDTH, SCREEN_HEIGHT)
        .opengl()
        .position_centered()
        .build()?;
    let _gl_context = window.gl_create_context().expect("Failed to create GL context");

    // Load OpenGL functions
    let gl = unsafe {
        egui_glow::painter::Context::from_loader_function(|name| {
            video.gl_get_proc_address(name) as *const _
        })
    };
    let mut painter = egui_glow::Painter::new(Arc::new(gl), "", None)?;

    // Setup Egui and SDL2 platform
    let mut platform = egui_sdl2_platform::Platform::new(window.size())?;
    let mut event_pump = sdl.event_pump().map_err(|e| anyhow::anyhow!("Failed to get SDL event pump: {}", e))?;

    // Initial settings
    let mut color = [0.0, 0.0, 0.0, 1.0]; // Background color
    let start_time = Instant::now();
    let mut timestep = TimeStep::new();

    let mut computer = Chip8Computer::new();
    let mut is_running: bool = false;
    computer.load_bytes_to_memory(0x200, &std::fs::read("resources/roms/3-corax+.ch8")?);

    // Main loop
    'main: loop {
        // Update the Egui platform with the current time
        platform.update_time(start_time.elapsed().as_secs_f64());

        // Begin Egui frame
        let ctx = platform.context();

        if is_running {
            computer.step_system();
        }

        egui::Window::new("Hello, world!").show(&ctx, |ui| {
            GemmaEguiSupport::video_view(&computer, ui);
            GemmaEguiSupport::memory_view(&computer, ui);
            GemmaEguiSupport::registers_view(&computer, ui);
        });

        // Process Egui frame
        let full_output = platform.end_frame(&mut video)?;
        let paint_jobs = platform.tessellate(&full_output);

        // Clear the screen with the current color
        unsafe {
            painter.gl().clear_color(color[0], color[1], color[2], 1.0);
            painter.gl().clear(COLOR_BUFFER_BIT);
        }

        // Paint Egui outputs and update textures
        let size = window.size();
        painter.paint_and_update_textures([size.0, size.1], 1.0, paint_jobs.as_slice(), &full_output.textures_delta);
        window.gl_swap_window();

        // Run the timestep logic
        timestep.run_this(|_| {});

        // Handle SDL2 events
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. }
                | Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::Escape), .. } => break 'main,
                Event::Window { window_id, win_event, .. } if window_id == window.id() => {
                    if let WindowEvent::Close = win_event {
                        break 'main;
                    }
                }
                Event::KeyUp { keycode: Some(sdl2::keyboard::Keycode::F3), .. } => {
                    println!("USER PRESSED F3 -> running");
                    is_running = true;
                }
                Event::KeyUp { keycode: Some(sdl2::keyboard::Keycode::F4), .. } => {
                    println!("USER PRESSED F4 -> stopping");
                    is_running = false;
                }
                Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::F5), .. } => {
                    println!("USER PRESSED F5 -> Step");
                    computer.step_system();
                }
                Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::F6), .. } => {
                    println!("USER PRESSED F6 -> RESET");
                    computer.reset();
                }
                Event::ControllerButtonDown { which, .. } => {
                    println!("PLAYER {which} DOWN");
                }
                Event::ControllerButtonDown { button, .. } => {
                    println!("BUTTON {:?}", button);
                }
                _ => platform.handle_event(&event, &sdl, &video),
            }
        }

        // Optionally log the frame rate
        if let Some(fps) = timestep.frame_rate() {
            println!("{:?} fps", fps);
        }
    }

    Ok(("").parse()?)
}

fn main() -> anyhow::Result<()> {
    pollster::block_on(run())?;
    Ok(())
}
