use crate::context::{AppContext, MessagesTab};
use crossterm::event::MouseEvent;
use ratatui::backend::Backend;
use ratatui::layout::Direction;
use ratatui::Terminal;
use std::fmt;
use wireman_event_handler::{EventHandler, KeyCode, KeyEvent};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ResponseEvents {
    NextTab,
    PrevTab,
    GoToRequest,
    CopyAsGrpCurl,
    CopyResponse,
    IncreaseSize,
    DecreaseSize,
    ToggleMainSplit,
}

impl fmt::Display for ResponseEvents {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let display_str = match self {
            ResponseEvents::NextTab => "Next Page",
            ResponseEvents::PrevTab => "Prev Page",
            ResponseEvents::GoToRequest => "Go to Request",
            ResponseEvents::CopyResponse => "Copy Response",
            ResponseEvents::CopyAsGrpCurl => "Copy as cURL",
            ResponseEvents::IncreaseSize => "Increase Size",
            ResponseEvents::DecreaseSize => "Decrease Size",
            ResponseEvents::ToggleMainSplit => "Toggle main split",
        };
        write!(f, "{display_str}")
    }
}

impl ResponseEventHandler {
    pub fn new() -> Self {
        Self {}
    }
}

pub struct ResponseEventHandler;

impl EventHandler for ResponseEventHandler {
    type Context = AppContext;

    type Event = ResponseEvents;

    fn handle_event(event: &ResponseEvents, ctx: &mut Self::Context) {
        match event {
            ResponseEvents::NextTab => {
                ctx.tab = ctx.tab.next();
            }
            ResponseEvents::PrevTab => {
                ctx.tab = ctx.tab.prev();
            }
            ResponseEvents::GoToRequest => {
                ctx.messages_tab = MessagesTab::Request;
            }
            ResponseEvents::CopyAsGrpCurl => {
                ctx.messages.borrow_mut().yank_grpcurl();
            }
            ResponseEvents::CopyResponse => {
                ctx.messages.borrow_mut().yank_response();
            }
            ResponseEvents::IncreaseSize => {
                ctx.messages.borrow_mut().request.decrease_window_size();
            }
            ResponseEvents::DecreaseSize => {
                ctx.messages.borrow_mut().request.increase_window_size();
            }
            ResponseEvents::ToggleMainSplit => {
                let mut ui = ctx.ui.borrow_mut();
                ui.main_split = match ui.main_split {
                    Direction::Vertical => Direction::Horizontal,
                    Direction::Horizontal => Direction::Vertical,
                };
            }
        }
    }

    fn key_event_mappings(ctx: &Self::Context) -> Vec<(KeyEvent, ResponseEvents)> {
        let disabled_root_events = ctx.disable_root_events;

        let go_to_request = match ctx.ui.borrow().main_split {
            Direction::Vertical => 'K',
            Direction::Horizontal => 'H',
        };

        let mut map = Vec::new();
        if !disabled_root_events {
            map.extend([
                (KeyEvent::new(KeyCode::Tab), ResponseEvents::NextTab),
                (KeyEvent::shift(KeyCode::BackTab), ResponseEvents::PrevTab),
                (
                    KeyEvent::shift(KeyCode::Char(go_to_request)),
                    ResponseEvents::GoToRequest,
                ),
                (
                    KeyEvent::shift(KeyCode::Char('Y')),
                    ResponseEvents::CopyResponse,
                ),
                (
                    KeyEvent::ctrl(KeyCode::Char('y')),
                    ResponseEvents::CopyAsGrpCurl,
                ),
                (
                    KeyEvent::new(KeyCode::Char('+')),
                    ResponseEvents::IncreaseSize,
                ),
                (
                    KeyEvent::new(KeyCode::Char('-')),
                    ResponseEvents::DecreaseSize,
                ),
                (
                    KeyEvent::alt(KeyCode::Char('s')),
                    ResponseEvents::ToggleMainSplit,
                ),
            ]);
        }
        map
    }

    fn pass_through_key_events<B: Backend>(
        event: &KeyEvent,
        ctx: &mut Self::Context,
        terminal: &mut Terminal<B>,
    ) {
        let response = &mut ctx.messages.borrow_mut().response.editor;
        response.on_key(event.clone().into(), terminal);
        ctx.disable_root_events = !response.normal_mode();
    }

    fn pass_through_mouse_events(event: &MouseEvent, ctx: &mut Self::Context) {
        let editor = &mut ctx.messages.borrow_mut().response.editor;
        editor.on_mouse(*event);
        ctx.disable_root_events = !editor.normal_mode();
    }

    fn pass_through_paste_events(text: String, ctx: &mut Self::Context) {
        let editor = &mut ctx.messages.borrow_mut().response.editor;
        editor.on_paste(text);
    }
}
