use crate::input::TemplateSource;
use crate::{Error, Result};
use handlebars::Handlebars;
use serde_json::Value;
use std::sync::Arc;
use tokio::sync::OnceCell;
static HANDLEBARS: OnceCell<Arc<Handlebars<'static>>> = OnceCell::const_new();
async fn init_handlebars() -> Arc<Handlebars<'static>> {
let mut hb = Handlebars::new();
hb.register_escape_fn(handlebars::html_escape);
hb.register_helper(
"format_currency",
Box::new(
|h: &handlebars::Helper,
_: &Handlebars,
_: &handlebars::Context,
_: &mut handlebars::RenderContext,
out: &mut dyn handlebars::Output|
-> handlebars::HelperResult {
let value = h
.param(0)
.and_then(|v| v.value().as_f64())
.ok_or_else(|| handlebars::RenderError::new("Invalid currency value"))?;
let symbol = h.param(1).and_then(|v| v.value().as_str()).unwrap_or("$");
let formatted = format!("{}{:.2}", symbol, value);
out.write(&formatted)?;
Ok(())
},
),
);
hb.register_helper(
"format_date",
Box::new(
|h: &handlebars::Helper,
_: &Handlebars,
_: &handlebars::Context,
_: &mut handlebars::RenderContext,
out: &mut dyn handlebars::Output|
-> handlebars::HelperResult {
let date_str = h
.param(0)
.and_then(|v| v.value().as_str())
.ok_or_else(|| handlebars::RenderError::new("Invalid date value"))?;
out.write(date_str)?;
Ok(())
},
),
);
Arc::new(hb)
}
async fn get_handlebars() -> Arc<Handlebars<'static>> {
HANDLEBARS
.get_or_init(|| async { init_handlebars().await })
.await
.clone()
}
pub async fn render_template(source: &TemplateSource, data: &Value) -> Result<String> {
let hb = get_handlebars().await;
let template_content = match source {
TemplateSource::Inline(template) => template.clone(),
TemplateSource::File(path) => {
if !path.exists() {
return Err(Error::TemplateNotFound(path.display().to_string()));
}
tokio::fs::read_to_string(path)
.await
.map_err(|e| Error::Template(format!("Failed to read template file: {}", e)))?
}
};
hb.render_template(&template_content, data)
.map_err(|e| Error::Template(format!("Template rendering failed: {}", e)))
}
pub async fn register_helper<F>(name: &str, helper: F)
where
F: handlebars::HelperDef + 'static,
{
let _ = (name, helper);
}