use edtui::{
    actions::SwitchMode,
    events::{KeyEventHandler, KeyEventRegister, KeyInput},
    EditorEventHandler, EditorMode, EditorState, EditorView, Lines,
};
use ratatui::{
    crossterm::event::{self, Event, KeyCode, KeyModifiers},
    prelude::*,
    widgets::Widget,
    DefaultTerminal,
};
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let mut terminal = ratatui::init();
    let result = run(&mut terminal);
    ratatui::restore();
    result
}

fn run(terminal: &mut DefaultTerminal) -> Result<(), Box<dyn Error>> {
    let mut app = App::new();
    loop {
        terminal.draw(|frame| frame.render_widget(&mut app, frame.area()))?;
        if let Event::Key(key) = event::read()? {
            if key.code == KeyCode::Char('c') && key.modifiers == KeyModifiers::CONTROL {
                break;
            }
            app.event_handler.on_key_event(key, &mut app.state);
        }
    }
    Ok(())
}

struct App {
    state: EditorState,
    event_handler: EditorEventHandler,
}

impl App {
    fn new() -> Self {
        let mut key_handler = KeyEventHandler::vim_mode();

        key_handler.insert(
            KeyEventRegister::n(vec![KeyInput::ctrl('x')]),
            SwitchMode(EditorMode::Insert),
        );

        key_handler.insert(
            KeyEventRegister::i(vec![KeyInput::ctrl('q')]),
            SwitchMode(EditorMode::Normal),
        );

        Self {
            state: EditorState::new(Lines::from(
                "Custom Keybindings Example

This example shows how to customize keybindings:
- Ctrl+x enters insert mode (instead of 'i')
- Ctrl+q exits insert mode (instead of Esc)

All other Vim keybindings remain active.

Try it out!
",
            )),
            event_handler: EditorEventHandler::new(key_handler),
        }
    }
}

impl Widget for &mut App {
    fn render(self, area: Rect, buf: &mut Buffer) {
        EditorView::new(&mut self.state)
            .wrap(true)
            .render(area, buf)
    }
}
