use std::error::Error;

use edtui::{EditorEventHandler, EditorState, EditorView};
use ratatui::crossterm::event::{self, Event, KeyCode, KeyModifiers};
use ratatui::{prelude::*, widgets::Widget};

use crate::term::Term;
use crate::theme::Theme;

pub type Result<T> = std::result::Result<T, Box<dyn Error>>;

#[derive(Default)]
pub struct App {
    pub context: AppContext,
    pub should_quit: bool,
}

#[derive(Default)]
pub struct AppContext {
    pub state: EditorState,
    pub event_handler: EditorEventHandler,
}

impl App {
    pub fn run(&mut self, term: &mut Term) -> Result<()> {
        while !self.should_quit {
            self.draw(term)?;
            self.handle_events()?;
        }
        Term::stop()?;
        Ok(())
    }

    pub fn draw(&mut self, term: &mut Term) -> Result<()> {
        let _ = term.draw(|f| f.render_widget(self, f.area()));
        Ok(())
    }

    pub fn handle_events(&mut self) -> Result<()> {
        let event = event::read()?;

        if let Event::Key(key) = event {
            if key.code == KeyCode::Char('c') && key.modifiers == KeyModifiers::CONTROL {
                self.should_quit = true;
                return Ok(());
            }
        };

        self.context
            .event_handler
            .on_event(event, &mut self.context.state);

        Ok(())
    }
}

impl Widget for &mut App {
    fn render(self, area: Rect, buf: &mut Buffer) {
        EditorView::new(&mut self.context.state)
            .theme(Theme::new().editor)
            .render(area, buf)
    }
}
