use crate::{
    doc_item::DocItem,
    module::{error::AutodocsError, group_functions, options::Options, ModuleMetadata},
};
#[derive(Debug)]
pub struct ModuleGlossary {
    pub content: String,
}
pub fn generate_module_glossary(
    engine: &rhai::Engine,
    options: &Options,
) -> Result<ModuleGlossary, AutodocsError> {
    let json_fns = engine
        .gen_fn_metadata_to_json(options.include_standard_packages)
        .map_err(|error| AutodocsError::Metadata(error.to_string()))?;
    let metadata = serde_json::from_str::<ModuleMetadata>(&json_fns)
        .map_err(|error| AutodocsError::Metadata(error.to_string()))?;
    generate_module_glossary_inner(options, None, "global", &metadata)
}
fn generate_module_glossary_inner(
    options: &Options,
    namespace: Option<String>,
    name: impl Into<String>,
    metadata: &ModuleMetadata,
) -> Result<ModuleGlossary, AutodocsError> {
    fn make_highlight(color: &str, item_type: &str, definition: &str) -> String {
        format!("- <Highlight color=\"{color}\">{item_type}</Highlight> <code>{{\"{definition}\"}}</code>\n",)
    }
    let name = name.into();
    let namespace = namespace.map_or(name.clone(), |namespace| namespace);
    let mut items = if let Some(types) = &metadata.custom_types {
        types
            .iter()
            .map(|metadata| DocItem::new_custom_type(metadata.clone(), &namespace, options))
            .collect::<Result<Vec<_>, AutodocsError>>()?
    } else {
        vec![]
    };
    items.extend(if let Some(functions) = &metadata.functions {
        let groups = group_functions(functions);
        groups
            .iter()
            .map(|(name, metadata)| DocItem::new_function(metadata, name, &namespace, options))
            .collect::<Result<Vec<_>, AutodocsError>>()?
    } else {
        vec![]
    });
    let items = options.items_order.order_items(items);
    let signatures = {
        let mut signatures = String::default();
        for item in &items {
            match item {
                DocItem::Function { metadata, .. } => {
                    for m in metadata {
                        let root_definition = m.generate_function_definition();
                        let serialized = root_definition.display();
                        signatures += &if serialized.starts_with("op ") {
                            make_highlight(
                                "#16c6f3",
                                root_definition.type_to_str(),
                                serialized.trim_start_matches("op "),
                            )
                        } else if serialized.starts_with("get ") {
                            make_highlight(
                                "#25c2a0",
                                root_definition.type_to_str(),
                                serialized.trim_start_matches("get "),
                            )
                        } else if serialized.starts_with("set ") {
                            make_highlight(
                                "#25c2a0",
                                root_definition.type_to_str(),
                                serialized.trim_start_matches("set "),
                            )
                        } else if serialized.starts_with("index get ") {
                            make_highlight(
                                "#25c2a0",
                                root_definition.type_to_str(),
                                serialized.trim_start_matches("index get "),
                            )
                        } else if serialized.starts_with("index set ") {
                            make_highlight(
                                "#25c2a0",
                                root_definition.type_to_str(),
                                serialized.trim_start_matches("index set "),
                            )
                        } else {
                            make_highlight(
                                "#C6cacb",
                                root_definition.type_to_str(),
                                serialized.trim_start_matches("fn "),
                            )
                        }
                    }
                }
                DocItem::CustomType { metadata, .. } => {
                    signatures += &make_highlight("#C6cacb", "type", &metadata.display_name)
                }
            }
        }
        signatures
    };
    let mut mg = ModuleGlossary {
        content: if name == "global" {
            format!(
                "{} \n\n### {}\n{}",
                include_str!("components/highlight.js"),
                name,
                signatures
            )
        } else {
            format!("### {}\n{}", name, signatures)
        },
    };
    if let Some(sub_modules) = &metadata.modules {
        for (sub_module, value) in sub_modules {
            mg.content.push_str(&{
                let mg = generate_module_glossary_inner(
                    options,
                    Some(format!("{}/{}", namespace, sub_module)),
                    sub_module,
                    &serde_json::from_value::<ModuleMetadata>(value.clone())
                        .map_err(|error| AutodocsError::Metadata(error.to_string()))?,
                )?;
                mg.content
            });
        }
    }
    Ok(mg)
}