use std::collections::HashMap;
use tera::{Context, Tera};

pub fn create_engine() -> Tera {
    let mut tera = Tera::default();

    tera.register_filter("tojson", tojson_filter);

    tera
}

pub fn render(
    template: &str,
    context: &HashMap<String, serde_json::Value>,
) -> Result<String, tera::Error> {
    let mut tera = create_engine();
    tera.add_raw_template("__inline__", template)?;

    let mut ctx = Context::new();
    for (key, value) in context {
        ctx.insert(key, value);
    }

    tera.render("__inline__", &ctx)
}

fn tojson_filter(
    value: &tera::Value,
    _args: &HashMap<String, tera::Value>,
) -> Result<tera::Value, tera::Error> {
    Ok(tera::Value::String(
        serde_json::to_string(value).unwrap_or_else(|_| value.to_string()),
    ))
}

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

    #[test]
    fn test_render_simple() {
        let mut ctx = HashMap::new();
        ctx.insert(
            "name".to_string(),
            serde_json::Value::String("world".to_string()),
        );

        let result = render("Hello {{ name }}!", &ctx).unwrap();
        assert_eq!(result, "Hello world!");
    }

    #[test]
    fn test_render_tojson_filter() {
        let mut ctx = HashMap::new();
        ctx.insert("data".to_string(), serde_json::json!({"key": "value"}));

        let result = render("{{ data | tojson }}", &ctx).unwrap();
        assert!(result.contains("key"));
        assert!(result.contains("value"));
    }
}
