use anyhow::{ensure, Result};
use crossterm::event;
use ratatui::{backend::CrosstermBackend, Terminal};
use std::{
    io::{self, IsTerminal},
    path::PathBuf,
};
use tb_ide::{
    app::{App, Execution},
    options,
    terminal::TerminalGuard,
};

fn main() -> Result<()> {
    let args: Vec<_> = std::env::args().skip(1).collect();
    if args.iter().any(|s| s == "--help" || s == "-h") {
        println!("tb [Projekt.mak|Modul.bas|Formular.frm]\nTerminal Basic IDE · mindestens 80×25\nF11: Menü · Alt+F4: Beenden");
        return Ok(());
    }
    ensure!(args.len() <= 1, "Aufruf: tb [Projektdatei]");
    ensure!(
        io::stdin().is_terminal() && io::stdout().is_terminal(),
        "tb benötigt ein interaktives Terminal; --help zeigt den Aufruf"
    );
    let base = std::env::current_dir()?;
    let mut app = App::new(&base, options::config_path()?, crossterm::terminal::size()?)?;
    if let Some(path) = args.first() {
        app.load_initial_project(PathBuf::from(path))?;
    }
    let mut guard = TerminalGuard::enter(io::stdout())?;
    let mut terminal = Terminal::new(CrosstermBackend::new(io::stdout()))?;
    let start = std::time::Instant::now();
    let mut last_draw = start - std::time::Duration::from_millis(16);
    let signals = tb_ui::signale::Signalquelle::neu();
    while !app.quit {
        if signals.abholen().is_some() {
            app.pause_execution();
        }
        let shell = if app.session.file_shell
            || matches!(app.execution, Execution::Running | Execution::Waiting)
        {
            app.session.host.shell_request.take()
        } else {
            None
        };
        if let Some(command) = shell {
            let result = guard.shell(&command, &signals);
            terminal.clear()?;
            let (cols, rows) = crossterm::terminal::size()?;
            app.handle(event::Event::Resize(cols, rows));
            if app.session.file_shell {
                app.session.file_shell = false;
                app.message = match result {
                    Ok(code) => format!("Shell beendet: {code}"),
                    Err(e) => format!("Shell: {e}"),
                };
            } else {
                app.session.host.shell_result =
                    Some(result.map_err(|_| tb_runtime::errors::RuntimeError(53)));
            }
        }
        if last_draw.elapsed() >= std::time::Duration::from_millis(16) {
            terminal.draw(|f| app.render(f))?;
            last_draw = std::time::Instant::now();
        }
        // Bounded input batch: both keyboard and VM make progress under load.
        for _ in 0..64 {
            if !event::poll(std::time::Duration::ZERO)? {
                break;
            }
            app.handle(event::read()?);
        }
        app.tick_execution(start.elapsed().as_millis() as u64);
        let timeout = if app.execution == Execution::Running {
            std::time::Duration::ZERO
        } else {
            std::time::Duration::from_millis(10)
        };
        if event::poll(timeout)? {
            app.handle(event::read()?);
        }
    }
    Ok(())
}
