mod protocol;
mod stdio;
mod ws;

use crate::app::{App, Message};
use anyhow::Result;
use serde_json;
use std::io::Write;
use std::sync::mpsc;
use std::thread;

pub struct IoHandler {
    receiver: mpsc::Receiver<Message>,
    #[allow(dead_code)]
    sender: mpsc::Sender<String>,
}

impl IoHandler {
    pub fn new() -> Result<Self> {
        let (_tx, rx) = mpsc::channel();
        let (cmd_tx, _cmd_rx) = mpsc::channel();

        // DO NOT spawn any IO threads that read from stdin!
        // The TUI needs exclusive access to stdin for keyboard input.
        // Future: use WebSocket or named pipe for backend communication.

        // Command sender thread (writes to stdout, but doesn't block stdin)
        thread::spawn(move || loop {
            match _cmd_rx.recv() {
                Ok(cmd) => {
                    let cmd_json = serde_json::json!({
                        "type": "command",
                        "text": cmd
                    });
                    if let Ok(json_str) = serde_json::to_string(&cmd_json) {
                        println!("{}", json_str);
                        let _ = std::io::stdout().flush();
                    }
                }
                Err(_) => break,
            }
        });

        Ok(Self {
            receiver: rx,
            sender: cmd_tx,
        })
    }

    pub fn update(&mut self, app: &mut App) -> Result<()> {
        // Non-blocking receive
        while let Ok(message) = self.receiver.try_recv() {
            app.update(message);
        }
        Ok(())
    }

    #[allow(dead_code)]
    pub fn send_command(&mut self, cmd: String) -> Result<()> {
        self.sender.send(cmd)?;
        Ok(())
    }
}
