use nalgebra_glm::Vec4;
use syntect::easy::HighlightLines;
use syntect::highlighting::ThemeSet;
use syntect::parsing::SyntaxSet;
use syntect::util::LinesWithEndings;

use crate::ecs::world::World;

pub struct SyntaxHighlighter {
    syntax_set: SyntaxSet,
    theme_set: ThemeSet,
}

impl SyntaxHighlighter {
    fn new() -> Self {
        Self {
            syntax_set: SyntaxSet::load_defaults_newlines(),
            theme_set: ThemeSet::load_defaults(),
        }
    }

    pub fn highlight(&self, text: &str, language: &str) -> Vec<Option<Vec4>> {
        let syntax = self
            .syntax_set
            .find_syntax_by_token(language)
            .unwrap_or_else(|| self.syntax_set.find_syntax_plain_text());

        let theme = &self.theme_set.themes["base16-mocha.dark"];
        let mut highlighter = HighlightLines::new(syntax, theme);

        let mut colors = Vec::new();

        for line in LinesWithEndings::from(text) {
            let ranges = highlighter
                .highlight_line(line, &self.syntax_set)
                .unwrap_or_default();

            for (style, fragment) in ranges {
                let r = style.foreground.r as f32 / 255.0;
                let g = style.foreground.g as f32 / 255.0;
                let b = style.foreground.b as f32 / 255.0;
                let a = style.foreground.a as f32 / 255.0;
                let color = Some(Vec4::new(r, g, b, a));
                for character in fragment.chars() {
                    if character != '\n' {
                        colors.push(color);
                    }
                }
            }
        }

        colors
    }
}

pub fn highlight_text_area(world: &mut World, text: &str, language: &str, text_slot: usize) {
    if world.resources.retained_ui.syntax_highlighter.is_none() {
        world.resources.retained_ui.syntax_highlighter = Some(SyntaxHighlighter::new());
    }

    let highlighter = world
        .resources
        .retained_ui
        .syntax_highlighter
        .as_ref()
        .unwrap();

    let colors = highlighter.highlight(text, language);

    world
        .resources
        .retained_ui
        .text_slot_character_colors
        .insert(text_slot, colors);
}
