use regex::{Captures, Regex};

use std::collections::HashMap;

use crate::config::SinglePageConfigs;
use crate::config_toml::NavbarItem;

type Data = HashMap<String, String>;

macro_rules! hashmap {
    ( $( $x:expr => $y:expr ),* ) => {
        {
            let mut temp_map = HashMap::new();
            $(
                temp_map.insert($x, $y);
            )*
            temp_map
        }
    };
}

pub struct Template {
    template: String,
    regex: Regex,
    if_regex: Regex,
}

impl Template {
    pub fn new<T: Into<String>>(template: T) -> Template {
        Template {
            template: template.into(),
            regex: Regex::new(r"\{\{(?P<to_replace>\w+)\}\}").unwrap(),
            if_regex: Regex::new(
                r"\{\{if (?P<boolean>\w+)\}\}(?P<rendered>(?:.|\n)*?)\{\{endif\}\}",
            ).unwrap(),
        }
    }

    pub fn render(&self, data: &Data) -> String {
        let template_clone = self.template.clone();

        let result = (&*self.if_regex
            .replace_all(&template_clone, |caps: &Captures| {
                if let Some(value) = data.get(&caps["boolean"]) {
                    if value == "true" {
                        caps["rendered"].to_owned()
                    } else {
                        String::new()
                    }
                } else {
                    String::new()
                }
            })).to_owned();

        let result = (&*self.regex.replace_all(&result, |caps: &Captures| {
            if let Some(text) = data.get(&caps["to_replace"]) {
                format!("{}", text)
            } else {
                String::new()
            }
        })).to_owned();

        result
    }

    pub fn css_tag_data_from(link: String, is_per_site: bool) -> Data {
        hashmap!(
            "link".to_owned() => link,
            "class".to_owned() => if is_per_site {"_default_js_meta".to_owned()} else {String::new()}
        )
    }

    pub fn navbar_item_data_from(item: NavbarItem) -> Data {
        let map = hashmap!(
            "title".to_owned() => item.title,
            "link".to_owned() => item.link,
            "image".to_owned() => item.image_url.unwrap_or(String::new())
        );

        map
    }

    pub fn page_data_from(
        config: SinglePageConfigs,
        navbar_content: String,
        before_navbar: String,
        before_content: String,
        after_content: String,
        css_tags: String,
        js_tags: String,
        content: String,
    ) -> Data {
        let favicon = config.page_config.page.favicon.unwrap_or(
            config
                .global_config
                .website
                .favicon
                .unwrap_or(String::new()),
        );

        let mut twitter_site = String::new();
        let mut twitter_creator = String::new();
        if let Some(twitter) = config.global_config.twitter.clone() {
            twitter_site = twitter.twitter_site;
            twitter_creator = twitter.twitter_creator;
        }

        let mut google_robots = String::new();
        let mut google_site_verification = String::new();
        if let Some(google) = config.global_config.google.clone() {
            google_robots = google.google_robots;
            google_site_verification = google.google_site_verification;
        }

        let map = hashmap!(
            "website_name".to_owned() => config.global_config.website.website_name,
            "page_title".to_owned() => config.page_config.page.title,
            "page_description".to_owned() => config.page_config.page.description,
            "favicon".to_owned() => favicon.to_owned(),

            "before_navbar".to_owned() => before_navbar,
            "before_content".to_owned() => before_content,
            "after_content".to_owned() => after_content,

            "css_links".to_owned() => css_tags,
            "javascript_links".to_owned() => js_tags,

            "use_default_css".to_owned() => config.global_config.website.use_default_css.to_string(),
            "use_default_js".to_owned() => config.global_config.website.use_default_js.to_string(),
            "navbar".to_owned() => config.global_config.navbar.is_some().to_string(),

            "navbar_content".to_owned() => navbar_content,
            "content".to_owned() => content,

            "mobile_viewport".to_owned() => config.global_config.website.mobile_viewport.unwrap_or(true).to_string(),
            "meta_description".to_owned() => config.global_config.website.meta_description.unwrap_or(true).to_string(),
            "charset".to_owned() => config.global_config.website.charset.unwrap_or("utf-8".to_owned()),
            "meta_og".to_owned() => config.global_config.website.meta_og.unwrap_or(true).to_string(),

            "twitter".to_owned() => config.global_config.twitter.is_some().to_string(),
            "google".to_owned() => config.global_config.google.is_some().to_string(),

            "twitter_site".to_owned() => twitter_site,
            "twitter_creator".to_owned() => twitter_creator,

            "google_robots".to_owned() => google_robots,
            "google_site_verification".to_owned() => google_site_verification
        );

        map
    }
}