use std::thread::sleep;
use std::time::Duration;
use std::{env, fs};

use crate::emulator::system::model::State;
use crate::emulator::system::model::{Command, Running};

pub fn run_cli() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize channels and read in configuration.
    let (cmd_sender, cmd_receiver) = std::sync::mpsc::channel();
    let (state_sender, state_reciever) = std::sync::mpsc::channel();

    // not needed for now.
    // let config = Config::load(Path::new(".dsa.emulator.toml"))?;

    crate::setup_emulator(cmd_receiver, state_sender, None);

    // run CLI.
    let mut state = State::new(cmd_sender, state_reciever);

    let mut bin_path: Option<String> = None;
    for (i, arg) in env::args().enumerate().skip(1) {
        // check for args --bin and <bin_path>
        if arg == "--bin" {
            bin_path = Some(env::args().nth(i + 1).expect("Binary path not provided"));
        }
    }

    let binary =
        fs::read(bin_path.expect("unreachable")).expect("unable to read binary file");
    state.send(Command::Write(0, binary));
    println!("{:?}", state.running);

    sleep(Duration::from_secs(1));

    state.update().expect("state failed to update");
    state
        .cmd_sender
        .send(Command::Start)
        .expect("state failed to update");
    loop {
        sleep(Duration::from_millis(20));
        state.send(Command::DisplayRequest);
        state.send(Command::RunningRequest);
        state.update().expect("update failed");

        for ch in state.serial_buff.drain(..) {
            print!("{}", ch as char);
        }

        if state.running == Running::Halted {
            break;
        }
    }

    Ok(())
}
