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

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

    writeln!(buffer, "// Generated by anaxa-config")?;
    writeln!(buffer, "#![allow(dead_code)]")?;
    writeln!(buffer)?;

    for item in items {
        if let Some(val) = values.get(&item.name) {
            if let Some(formatted) = item.config_type.format_value_rust(val) {
                writeln!(
                    buffer,
                    "pub const {}: {} = {};",
                    item.name,
                    item.config_type.rust_type(),
                    formatted
                )?;
            }
        }
    }

    Ok(buffer)
}

/// Generates a vector of strings suitable for `--cfg` flags.
pub fn generate_rust_cfgs(
    items: &[ConfigItem],
    values: &HashMap<String, toml::Value>,
) -> Result<Vec<String>> {
    let mut cfgs = Vec::new();

    for item in items {
        if let Some(val) = values.get(&item.name) {
            if item.config_type == ConfigType::Bool && val.as_bool() == Some(true) {
                cfgs.push(item.name.clone());
            }
        }
    }

    Ok(cfgs)
}

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

    #[test]
    fn test_generate_rust_consts() -> 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: "STR_VAL".to_string(),
                config_type: ConfigType::String,
                default: None,
                desc: "S".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(
            "STR_VAL".to_string(),
            toml::Value::String("hello".to_string()),
        );

        let code = generate_consts(&items, &values)?;
        assert!(code.contains("pub const ENABLE_A: bool = true;"));
        assert!(code.contains("pub const STR_VAL: &str = \"hello\";"));
        Ok(())
    }

    #[test]
    fn test_generate_rust_cfgs() -> 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,
        }];

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

        let cfgs = generate_rust_cfgs(&items, &values)?;
        assert_eq!(cfgs, vec!["ENABLE_A".to_string()]);
        Ok(())
    }
}
