use std::io::{ self, Write };

use open_wrapper::{ self, OpenReturnCodes };

fn main() {
    println!("Rust connect demo for open.dll");
    println!("(make sure open.dll is discoverable and open.lib is linked)\n");
    print_menu();

    let stdin = io::stdin();
    let mut state = ConnectionState::default();

    loop {
        print!("> ");
        if io::stdout().flush().is_err() {
            eprintln!("Failed to flush stdout.");
            break;
        }

        let mut line = String::new();
        if stdin.read_line(&mut line).is_err() {
            eprintln!("Failed to read input, exiting.");
            break;
        }

        let cmd = line.trim().to_lowercase();
        if cmd.is_empty() {
            continue;
        }

        match cmd.as_str() {
            "1" | "c" | "connect" => handle_connect(&mut state),
            "2" | "d" | "disconnect" => handle_disconnect(&mut state),
            // "3" | "g" | "get-speed" => handle_get_speed(),
            // "4" | "r" | "realtime" => handle_set_speed(100, "SetSimulationSpeed (100%)"),
            // "5" | "m" | "max" => handle_set_speed(u32::MAX, "SetSimulationSpeed (u32::MAX)"),
            "h" | "help" | "?" => print_menu(),
            "q" | "quit" | "exit" => {
                println!("Bye!");
                break;
            }
            _ => println!("Unknown command. Type `help` to see the list of commands."),
        }
    }
}

#[derive(Default)]
struct ConnectionState {
    connected: bool,
}

fn handle_connect(state: &mut ConnectionState) {
    if state.connected {
        println!("Already connected. Run `disconnect` first if you need a fresh session.");
        return;
    }

    let rc = call_and_report("Connect", || unsafe { open_wrapper::connect() });
    if rc.is_ok() {
        state.connected = true;
    }
}

fn handle_disconnect(state: &mut ConnectionState) {
    if !state.connected {
        println!("Not connected yet. Use `connect` first.");
        return;
    }

    let rc = call_and_report("Disconnect", || unsafe { open_wrapper::disconnect() });
    if rc.is_ok() {
        state.connected = false;
    }
}

// fn handle_get_speed() {
//     println!("GetSimulationSpeed called ...");
//     let mut sim_speed = 0u32;
//     let rc = unsafe { open_wrapper::get_simulation_speed(&mut sim_speed) };
//     if rc.is_ok() {
//         println!("Current simulation speed: {sim_speed}%");
//     }
//     println!("GetSimulationSpeed returned: {rc:?}");
// }

// fn handle_set_speed(value: u32, label: &str) {
//     println!("{label} called ...");
//     let rc = unsafe { open_wrapper::set_simulation_speed(value) };
//     println!("{label} returned: {rc:?}");
// }

fn call_and_report(action: &str, mut op: impl FnMut() -> OpenReturnCodes) -> OpenReturnCodes {
    println!("{action} called ...");
    let rc = op();
    println!("{action} returned: {rc:?}");
    rc
}

fn print_menu() {
    println!("Commands:");
    println!("  (1) connect       - connect to the running controller");
    println!("  (2) disconnect    - disconnect the session");
    println!("  (3) get-speed     - read the current simulation speed");
    println!("  (4) realtime      - set speed to 100%");
    println!("  (5) max           - set speed to u32::MAX");
    println!("  (h) help          - show this list");
    println!("  (q) quit          - exit the demo");
}
