use lazy_static::lazy_static;
use syntect::dumps::from_binary;
use syntect::highlighting::{Theme, ThemeSet};
use syntect::parsing::{SyntaxReference, SyntaxSet};

use crate::config::Config;
use syntect::html::{css_for_theme_with_class_style, ClassStyle};

lazy_static! {
    pub static ref SYNTAX_SET: SyntaxSet = {
        let ss: SyntaxSet =
            from_binary(include_bytes!("../../../sublime/syntaxes/newlines.packdump"));
        ss
    };
    pub static ref THEME_SET: ThemeSet =
        from_binary(include_bytes!("../../../sublime/themes/all.themedump"));
}

pub const CLASS_STYLE: ClassStyle = ClassStyle::SpacedPrefixed { prefix: "z-" };

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum HighlightSource {
    /// One of the built-in Zola syntaxes
    BuiltIn,
    /// Found in the extra syntaxes
    Extra,
    /// No language specified
    Plain,
    /// We didn't find the language in built-in and extra syntaxes
    NotFound,
}

pub struct SyntaxAndTheme<'config> {
    pub syntax: &'config SyntaxReference,
    pub syntax_set: &'config SyntaxSet,
    /// None if highlighting via CSS
    pub theme: Option<&'config Theme>,
    pub source: HighlightSource,
}

pub fn resolve_syntax_and_theme<'config>(
    language: Option<&'_ str>,
    config: &'config Config,
) -> SyntaxAndTheme<'config> {
    let theme = if config.markdown.highlight_theme != "css" {
        Some(&THEME_SET.themes[&config.markdown.highlight_theme])
    } else {
        None
    };

    if let Some(ref lang) = language {
        if let Some(ref extra_syntaxes) = config.markdown.extra_syntax_set {
            if let Some(syntax) = extra_syntaxes.find_syntax_by_token(lang) {
                return SyntaxAndTheme {
                    syntax,
                    syntax_set: extra_syntaxes,
                    theme,
                    source: HighlightSource::Extra,
                };
            }
        }
        // The JS syntax hangs a lot... the TS syntax is probably better anyway.
        // https://github.com/getzola/zola/issues/1241
        // https://github.com/getzola/zola/issues/1211
        // https://github.com/getzola/zola/issues/1174
        let hacked_lang = if *lang == "js" || *lang == "javascript" { "ts" } else { lang };
        if let Some(syntax) = SYNTAX_SET.find_syntax_by_token(hacked_lang) {
            SyntaxAndTheme {
                syntax,
                syntax_set: &SYNTAX_SET as &SyntaxSet,
                theme,
                source: HighlightSource::BuiltIn,
            }
        } else {
            SyntaxAndTheme {
                syntax: SYNTAX_SET.find_syntax_plain_text(),
                syntax_set: &SYNTAX_SET as &SyntaxSet,
                theme,
                source: HighlightSource::NotFound,
            }
        }
    } else {
        SyntaxAndTheme {
            syntax: SYNTAX_SET.find_syntax_plain_text(),
            syntax_set: &SYNTAX_SET as &SyntaxSet,
            theme,
            source: HighlightSource::Plain,
        }
    }
}

pub fn export_theme_css(theme_name: &str) -> String {
    let theme = &THEME_SET.themes[theme_name];
    css_for_theme_with_class_style(theme, CLASS_STYLE)
}
