use std::io::{stdout, Result};

use emmaemu::{chip8::{computer::Chip8Computer, video::Chip8Video}, constants::{CHIP8_MEMORY_SIZE, CHIP8_REGISTER_COUNT, CHIP8_ROM_SIZE, CHIP8_VIDEO_MEMORY}};
use ratatui::{
    backend::CrosstermBackend,
    crossterm::{
        event::{self, KeyCode, KeyEventKind},
        terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
        ExecutableCommand,
    },
    layout::{Alignment, Rect},
    style::{Style, Stylize},
    widgets::{List, Paragraph, Widget},
    Frame, Terminal,
};


fn system_memory_to_text_render(data_to_dump: [u8; 2048]) -> String {
    let mut to_return = String::new();

    for i in 0..256 {
        to_return += &format!("{:x}\t", data_to_dump[i as usize]).to_string();

        if ((i + 1) % CHIP8_REGISTER_COUNT) == 0 {
            to_return += "\n";
        }
    }

    to_return
}

fn dump_memory_to_console(data_to_dump: [u8; 2048]) {
    println!("STARTING TO DUMP MEMORY TO CONSOLE");
    println!("{}", system_memory_to_text_render(data_to_dump));
    println!("DONE DUMPING!");
    panic!("DONE DUMPING");
}

struct ControlKeyboard {

}

impl Widget for ControlKeyboard {
    fn render(self, area: Rect, buf: &mut ratatui::prelude::Buffer)
    where
        Self: Sized {
            let style = Style::new();
            buf.set_string(0, 0, "F1 to cycle foreground - F2 to cycle background", style)
    }
}


#[derive(Clone)]
struct AppState {
    pub menu_items: Vec<String>,
    pub selected_menu_item: i32,
    pub system: Chip8Computer,
}

impl Default for AppState {
    fn default() -> Self {
        println!("Creating new AppState");
        Self {
            menu_items: vec![
                "Step CPU <F5>".into(),
                "Reset CPU <F12>".into(),
                "Item 3".into(),
            ],
            selected_menu_item: 0,
            system: Chip8Computer {
                ..Default::default()
            },
        }
    }
}

fn main() -> Result<()> {
     stdout().execute(EnterAlternateScreen)?;
      enable_raw_mode()?;
      let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
     terminal.clear()?;

    let app = AppState::default();

    loop {
        // Draw Ui...
        terminal.draw(|frame| {
            frame.render_widget(app.system.memory, frame.area());
          //  frame.render_widget(app.control_keyboard, area);
            //render_cpu_state(app.system.clone(), frame);
           // render_video_state(app.system.video_memory, frame);
           // render_menu_list(app.clone(), frame);
        })?;
        // ...handle Events.
        if event::poll(std::time::Duration::from_millis(16))? {
            if let event::Event::Key(key) = event::read()? {
                match key.kind {
                    KeyEventKind::Press => match key.code {
                        KeyCode::F(5) => {
                            println!("Execute Next Instruction");
                        }
                        KeyCode::F(12) => {
                            println!("Resetting CPU");
                        }
                        KeyCode::Char('q') => { break; }
                        _ => (),
                    },
                    _ => (),
                }
            }
        }
    }

    //  stdout().execute(LeaveAlternateScreen)?;
    // disable_raw_mode()?;
    Ok(())
}

#[cfg(test)]
mod test {
    use emmaemu::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH};

    use crate::*;
    #[test]
    fn blank_screen_renders_to_text() {
        let test_video = Chip8Video::default();


        let blank_data: [bool; CHIP8_VIDEO_MEMORY] = [false; CHIP8_VIDEO_MEMORY];
        let blank_screen = (" ".repeat(CHIP8_VIDEO_WIDTH.try_into().unwrap()) + "\n")
            .repeat(CHIP8_VIDEO_HEIGHT.try_into().unwrap());
       
            assert_eq!(Chip8Video::new(blank_data).format_as_string(), blank_screen);
        }

    #[test]
    fn filled_screen_renders_to_text() {
        let filled_data: [bool; CHIP8_VIDEO_MEMORY] = [true; CHIP8_VIDEO_MEMORY];
        let filled_screen = ("*".repeat(CHIP8_VIDEO_WIDTH.try_into().unwrap()) + "\n")
            .repeat(CHIP8_VIDEO_HEIGHT.try_into().unwrap());
        assert_eq!(Chip8Video::new(filled_data).format_as_string(), filled_screen);
    }

    #[test]
    fn grid_pattern_renders_to_text() {
        let mut grid_data: [bool; CHIP8_VIDEO_MEMORY] = [false; CHIP8_VIDEO_MEMORY];
        let mut expected_data = String::new();
        for i in 0..CHIP8_VIDEO_MEMORY {
            grid_data[i] = (i % 2 == 0);
            if i % 2 == 0 {
                grid_data[i] = true;
                expected_data += "*";
            } else {
                grid_data[i] = false;
                expected_data += " ";
            }
            if (i as i32 % CHIP8_VIDEO_WIDTH as i32 == CHIP8_VIDEO_WIDTH - 1) {
                expected_data += "\n";
            }
        }

        assert_eq!(Chip8Video::new(grid_data).format_as_string(), expected_data);
    }
}
