use crate::model::docs::{self, DocEntry, DOCS};
use crate::state::{HelpFocus, UiState};

use DocEntry::{Section, Topic};

pub fn toggle_focus(ui: &mut UiState) {
    ui.help_focus = match ui.help_focus {
        HelpFocus::Topics => HelpFocus::Content,
        HelpFocus::Content => HelpFocus::Topics,
    };
}

pub fn select_topic(ui: &mut UiState, index: usize) {
    if index < docs::topic_count() {
        ui.help_topic = index;
        ui.help_on_section = None;
    }
}

#[derive(Clone, Copy)]
enum VisibleItem {
    Topic(usize),
    Section(usize),
}

fn visible_items(collapsed: &[bool]) -> Vec<VisibleItem> {
    let mut result = Vec::new();
    let mut section_idx = 0usize;
    let mut topic_idx = 0usize;
    let mut skipping = false;
    for entry in DOCS.iter() {
        match entry {
            Section(_) => {
                let is_collapsed = collapsed.get(section_idx).copied().unwrap_or(false);
                if is_collapsed {
                    result.push(VisibleItem::Section(section_idx));
                }
                skipping = is_collapsed;
                section_idx += 1;
            }
            Topic(_, _) => {
                if !skipping {
                    result.push(VisibleItem::Topic(topic_idx));
                }
                topic_idx += 1;
            }
        }
    }
    result
}

fn find_current(items: &[VisibleItem], ui: &UiState) -> usize {
    if let Some(s) = ui.help_on_section {
        items
            .iter()
            .position(|v| matches!(v, VisibleItem::Section(idx) if *idx == s))
            .unwrap_or(0)
    } else {
        items
            .iter()
            .position(|v| matches!(v, VisibleItem::Topic(idx) if *idx == ui.help_topic))
            .unwrap_or(0)
    }
}

fn apply_selection(ui: &mut UiState, item: VisibleItem) {
    match item {
        VisibleItem::Topic(idx) => {
            ui.help_topic = idx;
            ui.help_on_section = None;
        }
        VisibleItem::Section(idx) => {
            ui.help_on_section = Some(idx);
        }
    }
}

pub fn next_topic(ui: &mut UiState, n: usize) {
    let items = visible_items(&ui.help_collapsed);
    if items.is_empty() {
        return;
    }
    let cur = find_current(&items, ui);
    let next = (cur + n) % items.len();
    apply_selection(ui, items[next]);
    ui.help_focused_block = None;
}

pub fn prev_topic(ui: &mut UiState, n: usize) {
    let items = visible_items(&ui.help_collapsed);
    if items.is_empty() {
        return;
    }
    let cur = find_current(&items, ui);
    let next = (cur + items.len() - (n % items.len())) % items.len();
    apply_selection(ui, items[next]);
    ui.help_focused_block = None;
}

pub fn scroll_down(ui: &mut UiState, n: usize) {
    let max = ui.help_max_scroll.get();
    let s = ui.help_scroll_mut();
    *s = s.saturating_add(n).min(max);
}

pub fn scroll_up(ui: &mut UiState, n: usize) {
    let s = ui.help_scroll_mut();
    *s = s.saturating_sub(n);
}

pub fn activate_search(ui: &mut UiState) {
    ui.help_search_active = true;
}

pub fn clear_search(ui: &mut UiState) {
    ui.help_search_query.clear();
    ui.help_search_active = false;
}

pub fn search_input(ui: &mut UiState, c: char) {
    ui.help_search_query.push(c);
    if let Some((topic, line)) = docs::find_match(&ui.help_search_query) {
        ui.help_topic = topic;
        ui.help_on_section = None;
        ui.help_scrolls[topic] = line;
    }
}

pub fn search_backspace(ui: &mut UiState) {
    ui.help_search_query.pop();
    if ui.help_search_query.is_empty() {
        return;
    }
    if let Some((topic, line)) = docs::find_match(&ui.help_search_query) {
        ui.help_topic = topic;
        ui.help_on_section = None;
        ui.help_scrolls[topic] = line;
    }
}

pub fn search_confirm(ui: &mut UiState) {
    ui.help_search_active = false;
}
