pub enum DocEntry {
    Section(&'static str),
    Topic(&'static str, &'static str),
}

use DocEntry::{Section, Topic};

pub const DOCS: &[DocEntry] = &[
    // Getting Started
    Section("Getting Started"),
    Topic("Welcome", include_str!("../../docs/welcome.md")),
    Topic(
        "Navigation",
        include_str!("../../docs/getting-started/navigation.md"),
    ),
    Topic(
        "The Big Picture",
        include_str!("../../docs/getting-started/big_picture.md"),
    ),
    Topic(
        "Banks & Patterns",
        include_str!("../../docs/getting-started/banks_patterns.md"),
    ),
    Topic(
        "Stage / Commit",
        include_str!("../../docs/getting-started/staging.md"),
    ),
    Topic(
        "Using the Sequencer",
        include_str!("../../docs/getting-started/grid.md"),
    ),
    Topic(
        "Editing a Step",
        include_str!("../../docs/getting-started/editing.md"),
    ),
    Topic(
        "The Audio Engine",
        include_str!("../../docs/getting-started/engine.md"),
    ),
    Topic(
        "Options",
        include_str!("../../docs/getting-started/options.md"),
    ),
    Topic(
        "Saving & Loading",
        include_str!("../../docs/getting-started/saving.md"),
    ),
    Topic(
        "The Sample Browser",
        include_str!("../../docs/getting-started/samples.md"),
    ),
    // Forth fundamentals
    Section("Cagire's Forth"),
    Topic(
        "About Forth",
        include_str!("../../docs/forth/about_forth.md"),
    ),
    Topic(
        "The Dictionary",
        include_str!("../../docs/forth/dictionary.md"),
    ),
    Topic("The Stack", include_str!("../../docs/forth/stack.md")),
    Topic(
        "Creating Words",
        include_str!("../../docs/forth/definitions.md"),
    ),
    Topic(
        "Control Flow",
        include_str!("../../docs/forth/control_flow.md"),
    ),
    Topic("The Prelude", include_str!("../../docs/forth/prelude.md")),
    Topic(
        "Cagire vs Classic",
        include_str!("../../docs/forth/oddities.md"),
    ),
    // Audio Engine
    Section("Building sounds"),
    Topic("Introduction", include_str!("../../docs/engine/intro.md")),
    Topic("Settings", include_str!("../../docs/engine/settings.md")),
    Topic("Sources", include_str!("../../docs/engine/sources.md")),
    Topic("Samples", include_str!("../../docs/engine/samples.md")),
    Topic("Wavetables", include_str!("../../docs/engine/wavetable.md")),
    Topic("Filters", include_str!("../../docs/engine/filters.md")),
    Topic(
        "Modulation",
        include_str!("../../docs/engine/modulation.md"),
    ),
    Topic(
        "Distortion",
        include_str!("../../docs/engine/distortion.md"),
    ),
    Topic("Space & Time", include_str!("../../docs/engine/space.md")),
    Topic(
        "Audio-Rate Mod",
        include_str!("../../docs/engine/audio_modulation.md"),
    ),
    Topic("Words & Sounds", include_str!("../../docs/engine/words.md")),
    // MIDI
    Section("Branching out"),
    Topic("Introduction", include_str!("../../docs/midi/intro.md")),
    Topic("MIDI Output", include_str!("../../docs/midi/output.md")),
    Topic("MIDI Input", include_str!("../../docs/midi/input.md")),
    // Tutorials
    Section("Tutorials"),
    Topic(
        "Randomness",
        include_str!("../../docs/tutorials/randomness.md"),
    ),
    Topic(
        "Notes & Harmony",
        include_str!("../../docs/tutorials/harmony.md"),
    ),
    Topic(
        "Generators",
        include_str!("../../docs/tutorials/generators.md"),
    ),
    Topic("Timing with at", include_str!("../../docs/tutorials/at.md")),
    Topic(
        "Using Variables",
        include_str!("../../docs/tutorials/variables.md"),
    ),
    Topic(
        "Recording",
        include_str!("../../docs/tutorials/recording.md"),
    ),
    Topic(
        "Soundfonts",
        include_str!("../../docs/tutorials/soundfont.md"),
    ),
    Topic(
        "Sharing",
        include_str!("../../docs/tutorials/sharing.md"),
    ),
];

pub fn topic_count() -> usize {
    DOCS.iter().filter(|e| matches!(e, Topic(_, _))).count()
}

pub fn section_count() -> usize {
    DOCS.iter().filter(|e| matches!(e, Section(_))).count()
}

pub fn section_index_for_topic(topic_idx: usize) -> usize {
    let mut section: usize = 0;
    let mut topic: usize = 0;
    for entry in DOCS.iter() {
        match entry {
            Section(_) => section += 1,
            Topic(_, _) => {
                if topic == topic_idx {
                    return section.saturating_sub(1);
                }
                topic += 1;
            }
        }
    }
    section.saturating_sub(1)
}

pub fn first_topic_in_section(section_idx: usize) -> Option<usize> {
    let mut section: usize = 0;
    let mut topic: usize = 0;
    let mut in_target = false;
    for entry in DOCS.iter() {
        match entry {
            Section(_) => {
                if in_target {
                    return None;
                }
                if section == section_idx {
                    in_target = true;
                }
                section += 1;
            }
            Topic(_, _) => {
                if in_target {
                    return Some(topic);
                }
                topic += 1;
            }
        }
    }
    None
}

pub fn get_topic(index: usize) -> Option<(&'static str, &'static str)> {
    DOCS.iter()
        .filter_map(|e| match e {
            Topic(name, content) => Some((*name, *content)),
            Section(_) => None,
        })
        .nth(index)
}

pub fn find_match(query: &str) -> Option<(usize, usize)> {
    let query = query.to_lowercase();
    for (topic_idx, (_, content)) in DOCS
        .iter()
        .filter_map(|e| match e {
            Topic(name, content) => Some((*name, *content)),
            Section(_) => None,
        })
        .enumerate()
    {
        for (line_idx, line) in content.lines().enumerate() {
            if line.to_lowercase().contains(&query) {
                return Some((topic_idx, line_idx));
            }
        }
    }
    None
}
