use clap::Parser;

use common::prelude::Instruction;
use dsa::{Emulator, Page, args::DsaArgs, frontend::run_app};
use std::thread;

const STACK_SIZE: usize = 1024 * 1024 * 16;

fn main() {
    let args = DsaArgs::parse();

    let mut emulator = Emulator::new().apply_memory_map(args.get_memory_map());

    let mem_handle = emulator.memory_mut().clone();
    let state = emulator.state_handle();

    if let Some(bin) = args.get_binary() {
        for (i, ch) in bin.chunks(4).enumerate() {
            let instruction = Instruction(u32::from_le_bytes(ch.try_into().unwrap()));
            let hex = ch
                .iter()
                .map(|b| format!("{:02X}", b))
                .collect::<Vec<_>>()
                .join(" ");
            let chars = ch
                .iter()
                .map(|b| {
                    if b.is_ascii_graphic() {
                        *b as char
                    } else {
                        '.'
                    }
                })
                .collect::<String>();
            println!("{:04X}: {:<12} {:4} {:?}", i * 4, hex, chars, instruction);
        }

        let program: Vec<Page> = Page::paginate(&bin).collect();

        for (i, page) in program.iter().enumerate() {
            emulator.memory_mut().write_page(i as u32 * 4096, &page);
        }
    }

    let _runner = thread::Builder::new()
        .stack_size(STACK_SIZE)
        .spawn(move || emulator.run().unwrap())
        .unwrap();

    run_app(state, mem_handle).unwrap()
}
