use mlua::{Function, Lua, Result as LuaResult, Table, Value};
use std::collections::HashMap;
use crate::templates::engine::{RenderContext, render_string};
use crate::vars::datemath::{evaluate_date_expr, is_date_expr, parse_date_expr};
pub fn register_mdv_table(lua: &Lua) -> LuaResult<()> {
let mdv = lua.create_table()?;
mdv.set("date", create_date_fn(lua)?)?;
mdv.set("render", create_render_fn(lua)?)?;
mdv.set("is_date_expr", create_is_date_expr_fn(lua)?)?;
lua.globals().set("mdv", mdv)?;
Ok(())
}
fn create_date_fn(lua: &Lua) -> LuaResult<Function> {
lua.create_function(|_, args: (String, Option<String>)| {
let (expr, format_override) = args;
let mut parsed =
parse_date_expr(&expr).map_err(|e| mlua::Error::runtime(e.to_string()))?;
if let Some(fmt) = format_override {
parsed.format = Some(fmt);
}
Ok(evaluate_date_expr(&parsed))
})
}
fn create_render_fn(lua: &Lua) -> LuaResult<Function> {
lua.create_function(|_, args: (String, Table)| {
let (template, ctx_table) = args;
let mut ctx: RenderContext = HashMap::new();
for pair in ctx_table.pairs::<String, Value>() {
let (key, value) = pair?;
let str_value = lua_value_to_string(&key, value)?;
ctx.insert(key, str_value);
}
render_string(&template, &ctx).map_err(|e| mlua::Error::runtime(e.to_string()))
})
}
fn create_is_date_expr_fn(lua: &Lua) -> LuaResult<Function> {
lua.create_function(|_, s: String| Ok(is_date_expr(&s)))
}
fn lua_value_to_string(key: &str, value: Value) -> LuaResult<String> {
match value {
Value::String(s) => Ok(s.to_str()?.to_string()),
Value::Integer(i) => Ok(i.to_string()),
Value::Number(n) => Ok(n.to_string()),
Value::Boolean(b) => Ok(b.to_string()),
Value::Nil => Ok(String::new()),
_ => Err(mlua::Error::runtime(format!(
"context value for '{}' must be string, number, boolean, or nil",
key
))),
}
}