use std::{
    cell::{OnceCell, RefCell},
    future::Future,
    rc::Rc,
};

use futures_util::FutureExt;
use ratzilla::{
    backend::canvas::CanvasBackendOptions, event::KeyCode, ratatui::Terminal, CanvasBackend,
    WebRenderer,
};
use wasm_bindgen::prelude::*;

mod utils;

use crate::app::{App, AppExecutor};

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

struct WasmBindgenExecutor;

impl AppExecutor for WasmBindgenExecutor {
    fn execute<T: 'static>(
        &self,
        future: impl Future<Output = T> + 'static,
        output_cell: Rc<OnceCell<T>>,
    ) {
        wasm_bindgen_futures::spawn_local(future.map(move |output| {
            let _ = output_cell.set(output);
        }));
    }
}

#[wasm_bindgen]
pub fn run(grid_id: &str) {
    utils::set_panic_hook();

    let backend = CanvasBackend::new_with_options(
        CanvasBackendOptions::new()
            .grid_id(grid_id)
            .font(String::from("16px Fira Code")),
    )
    .unwrap();
    let terminal = Terminal::new(backend).unwrap();

    let app = Rc::new(RefCell::new(App::new(WasmBindgenExecutor)));

    terminal.on_key_event({
        let app = Rc::clone(&app);
        move |event| match event.code {
            KeyCode::Left => app.borrow_mut().prev_tab(),
            KeyCode::Right => app.borrow_mut().next_tab(),
            KeyCode::Char(c) => app.borrow_mut().add_char_to_number_guess(c),
            _ => {}
        }
    });

    terminal.draw_web({
        let app = Rc::clone(&app);
        move |frame| app.borrow_mut().draw(frame)
    })
}
