use std::{collections::HashMap, sync::LazyLock};

use ratatui::{
    crossterm::event::{KeyCode, KeyModifiers},
    layout::Constraint,
    style::{Color, Modifier, Style},
    widgets::Cell,
};
use ratzgo::{
    core::{Element, OnKeyBuilder},
    scroll::ScrollAction,
    widget::{BorderType, Row, TableState, block, table},
};
use serde::Deserialize;

use crate::ui::HelpMsg;

static KEYMAP: LazyLock<HashMap<&'static str, Vec<KeyMapItem>>> = LazyLock::new(|| {
    toml::from_str(include_str!(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/templates/keymap.toml"
    )))
    .unwrap_or_default()
});

pub fn keymap_at(page: &str) -> &[KeyMapItem] {
    &KEYMAP[page]
}

pub fn keymap<'a>(state: &'a mut TableState, page: &str) -> impl Into<Element<'a, HelpMsg>> {
    let inner = table(state)
        .header(
            Row::new(vec!["Key", "Description"])
                .style(
                    Style::default()
                        .fg(Color::Yellow)
                        .add_modifier(Modifier::BOLD),
                )
                .bottom_margin(1),
        )
        .widths([Constraint::Length(16), Constraint::Min(10)])
        .rows(KEYMAP[page].iter().map(|KeyMapItem { key, desc }| {
            Row::new(vec![
                Cell::from(*key).style(
                    Style::default()
                        .fg(Color::Cyan)
                        .add_modifier(Modifier::BOLD),
                ),
                Cell::from(*desc).style(Style::default().fg(Color::Gray)),
            ])
        }))
        .decorate(|v| {
            v.row_highlight_style(
                Style::default()
                    .fg(Color::Black)
                    .bg(Color::Cyan)
                    .add_modifier(Modifier::BOLD),
            )
            .highlight_symbol("")
        })
        .on_key_with(|k| {
            let msg = match k.code {
                KeyCode::Char('j') => HelpMsg::Scroll(ScrollAction::Fixed(1)),
                KeyCode::Char('k') => HelpMsg::Scroll(ScrollAction::Fixed(-1)),
                KeyCode::Char('d') if k.modifiers == KeyModifiers::CONTROL => {
                    HelpMsg::Scroll(ScrollAction::Viewport(50))
                }
                KeyCode::Char('u') if k.modifiers == KeyModifiers::CONTROL => {
                    HelpMsg::Scroll(ScrollAction::Viewport(-50))
                }
                KeyCode::Char('f') if k.modifiers == KeyModifiers::CONTROL => {
                    HelpMsg::Scroll(ScrollAction::Viewport(100))
                }
                KeyCode::Char('b') if k.modifiers == KeyModifiers::CONTROL => {
                    HelpMsg::Scroll(ScrollAction::Viewport(-100))
                }
                KeyCode::Esc => HelpMsg::Close,
                _ => return None,
            };
            Some(msg)
        });

    block(inner).bordered().border_type(BorderType::Rounded)
}

#[derive(Debug, Deserialize)]
pub struct KeyMapItem {
    key: &'static str,
    desc: &'static str,
}