use crate::schema::{ConfigItem, ConfigType};
use anyhow::Result;
use std::collections::HashMap;
use std::fmt::Write;

pub fn generate(items: &[ConfigItem], values: &HashMap<String, toml::Value>) -> Result<String> {
    let mut buffer = String::new();

    writeln!(buffer, "/* Generated by anaxa-config */")?;
    writeln!(buffer, "#ifndef _AUTOCONF_H_")?;
    writeln!(buffer, "#define _AUTOCONF_H_")?;
    writeln!(buffer)?;

    for item in items {
        if let Some(val) = values.get(&item.name) {
            write_item_define(&mut buffer, item, val)?;
        }
    }

    writeln!(buffer)?;
    writeln!(buffer, "#endif /* _AUTOCONF_H_ */")?;

    Ok(buffer)
}

fn write_item_define(buffer: &mut String, item: &ConfigItem, val: &toml::Value) -> Result<()> {
    let name = format!("CONFIG_{}", item.name);

    if item.config_type == ConfigType::Bool && val.as_bool() == Some(false) {
        writeln!(buffer, "/* {} is not set */", name)?;
    } else if let Some(formatted) = item.config_type.format_value_c(val) {
        writeln!(buffer, "#define {} {}", name, formatted)?;
    }
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::schema::ConfigType;

    #[test]
    fn test_generate_c() -> Result<()> {
        let items = vec![
            ConfigItem {
                name: "ENABLE_A".to_string(),
                config_type: ConfigType::Bool,
                default: None,
                desc: "A".to_string(),
                depends_on: None,
                help: None,
                options: None,
                feature: None,
                range: None,
                regex: None,
            },
            ConfigItem {
                name: "MAX_B".to_string(),
                config_type: ConfigType::Int,
                default: None,
                desc: "B".to_string(),
                depends_on: None,
                help: None,
                options: None,
                feature: None,
                range: None,
                regex: None,
            },
        ];

        let mut values = HashMap::new();
        values.insert("ENABLE_A".to_string(), toml::Value::Boolean(true));
        values.insert("MAX_B".to_string(), toml::Value::Integer(42));

        let code = generate(&items, &values)?;
        assert!(code.contains("#define CONFIG_ENABLE_A 1"));
        assert!(code.contains("#define CONFIG_MAX_B 42"));
        Ok(())
    }
}
