use std::cell::{Cell, RefCell};
use std::time::{Duration, Instant};

use cagire_markdown::ParsedMarkdown;
use cagire_ratatui::Sparkles;
use tachyonfx::{fx, Effect, EffectManager, Interpolation, Motion};

use crate::page::Page;
use crate::state::effects::FxId;
use crate::state::{ColorScheme, Modal};

#[derive(Clone, Copy, PartialEq, Eq, Default)]
pub enum MinimapMode {
    #[default]
    Hidden,
    Timed(Instant),
    Sticky,
}

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum FlashKind {
    #[default]
    Success,
    Error,
    Info,
}

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum DictFocus {
    #[default]
    Categories,
    Words,
}

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum HelpFocus {
    #[default]
    Topics,
    Content,
}

pub struct UiState {
    pub sparkles: Sparkles,
    pub status_message: Option<String>,
    pub flash_until: Option<Instant>,
    pub flash_kind: FlashKind,
    pub modal: Modal,
    pub help_focus: HelpFocus,
    pub help_topic: usize,
    pub help_scrolls: Vec<usize>,
    pub help_search_active: bool,
    pub help_search_query: String,
    pub help_focused_block: Option<usize>,
    pub help_parsed: RefCell<Vec<Option<ParsedMarkdown>>>,
    pub dict_focus: DictFocus,
    pub dict_category: usize,
    pub dict_scrolls: Vec<usize>,
    pub dict_search_query: String,
    pub dict_search_active: bool,
    pub help_max_scroll: Cell<usize>,
    pub dict_max_scroll: Cell<usize>,
    pub help_collapsed: Vec<bool>,
    pub help_on_section: Option<usize>,
    pub dict_collapsed: Vec<bool>,
    pub dict_on_section: Option<usize>,
    pub show_title: bool,
    pub runtime_highlight: bool,
    pub show_completion: bool,
    pub minimap: MinimapMode,
    pub color_scheme: ColorScheme,
    pub hue_rotation: f32,
    pub effects: RefCell<EffectManager<FxId>>,
    pub modal_fx: RefCell<Option<Effect>>,
    pub title_fx: RefCell<Option<Effect>>,
    pub prev_modal_open: bool,
    pub prev_page: Page,
    pub prev_show_title: bool,
    pub onboarding_dismissed: Vec<String>,
    pub performance_mode: bool,
    pub font: String,
    pub zoom_factor: f32,
    pub window_width: u32,
    pub window_height: u32,
    pub load_demo_on_startup: bool,
    pub demo_index: usize,
    pub nav_indicator_until: Option<Instant>,
    pub nav_fx: RefCell<Option<Effect>>,
    pub last_click: Option<(Instant, u16, u16)>,
}

impl Default for UiState {
    fn default() -> Self {
        Self {
            sparkles: Sparkles::default(),
            status_message: None,
            flash_until: None,
            flash_kind: FlashKind::Success,
            modal: Modal::None,
            help_focus: HelpFocus::default(),
            help_topic: 0,
            help_scrolls: vec![0; crate::model::docs::topic_count()],
            help_search_active: false,
            help_search_query: String::new(),
            help_focused_block: None,
            help_parsed: RefCell::new(
                (0..crate::model::docs::topic_count())
                    .map(|_| None)
                    .collect(),
            ),
            dict_focus: DictFocus::default(),
            dict_category: 0,
            dict_scrolls: vec![0; crate::model::categories::category_count()],
            dict_search_query: String::new(),
            dict_search_active: false,
            help_max_scroll: Cell::new(usize::MAX),
            dict_max_scroll: Cell::new(usize::MAX),
            help_collapsed: vec![false; crate::model::docs::section_count()],
            help_on_section: None,
            dict_collapsed: vec![false; crate::model::categories::section_count()],
            dict_on_section: None,
            show_title: true,
            runtime_highlight: false,
            show_completion: true,
            minimap: MinimapMode::Hidden,
            color_scheme: ColorScheme::default(),
            hue_rotation: 0.0,
            effects: RefCell::new(EffectManager::default()),
            modal_fx: RefCell::new(None),
            title_fx: RefCell::new(Some(fx::coalesce((400, Interpolation::QuadOut)))),
            prev_modal_open: false,
            prev_page: Page::default(),
            prev_show_title: true,
            onboarding_dismissed: Vec::new(),
            performance_mode: false,
            font: "8x13".to_string(),
            zoom_factor: 1.5,
            window_width: 1200,
            window_height: 800,
            load_demo_on_startup: true,
            demo_index: 0,
            nav_indicator_until: None,
            nav_fx: RefCell::new(None),
            last_click: None,
        }
    }
}

impl UiState {
    pub fn help_scroll(&self) -> usize {
        self.help_scrolls[self.help_topic]
    }

    pub fn help_scroll_mut(&mut self) -> &mut usize {
        &mut self.help_scrolls[self.help_topic]
    }

    pub fn dict_scroll(&self) -> usize {
        self.dict_scrolls[self.dict_category]
    }

    pub fn dict_scroll_mut(&mut self) -> &mut usize {
        &mut self.dict_scrolls[self.dict_category]
    }

    pub fn flash(&mut self, msg: &str, duration_ms: u64, kind: FlashKind) {
        self.status_message = Some(msg.to_string());
        self.flash_until = Some(Instant::now() + Duration::from_millis(duration_ms));
        self.flash_kind = kind;
    }

    pub fn flash_kind(&self) -> Option<FlashKind> {
        if self.is_flashing() {
            Some(self.flash_kind)
        } else {
            None
        }
    }

    pub fn set_status(&mut self, msg: String) {
        self.status_message = Some(msg);
    }

    pub fn clear_status(&mut self) {
        self.status_message = None;
    }

    pub fn is_flashing(&self) -> bool {
        self.flash_until
            .map(|t| Instant::now() < t)
            .unwrap_or(false)
    }

    pub fn show_minimap(&self) -> bool {
        match self.minimap {
            MinimapMode::Hidden => false,
            MinimapMode::Timed(until) => Instant::now() < until,
            MinimapMode::Sticky => true,
        }
    }

    pub fn dismiss_minimap(&mut self) {
        self.minimap = MinimapMode::Hidden;
    }

    pub fn show_nav_indicator(&mut self, duration_ms: u64, direction: Motion) {
        self.nav_indicator_until = Some(Instant::now() + Duration::from_millis(duration_ms));
        let bg = crate::theme::get().ui.bg;
        *self.nav_fx.borrow_mut() = Some(fx::fade_from_fg(bg, (150, Interpolation::QuadOut)));
        crate::state::effects::nav_sweep(self, direction);
    }

    pub fn nav_indicator_visible(&self) -> bool {
        self.nav_indicator_until
            .map(|t| Instant::now() < t)
            .unwrap_or(false)
    }

    pub fn invalidate_help_cache(&self) {
        self.help_parsed
            .borrow_mut()
            .iter_mut()
            .for_each(|slot| *slot = None);
    }
}
