//! Custom Tera filters for templates

use std::collections::HashMap;
use tera::{Filter, Result as TeraResult, Value};

/// Filter for formatting dates
///
/// Usage: `{{ "2024-12-13" | date(format="%d/%m/%Y") }}`
pub struct DateFormatFilter;

impl Filter for DateFormatFilter {
    fn filter(&self, value: &Value, args: &HashMap<String, Value>) -> TeraResult<Value> {
        let date_str = value
            .as_str()
            .ok_or_else(|| tera::Error::msg("Value must be a string"))?;

        let format = args
            .get("format")
            .and_then(|v| v.as_str())
            .unwrap_or("%Y-%m-%d");

        match chrono::NaiveDate::parse_from_str(date_str, "%Y-%m-%d") {
            Ok(date) => Ok(Value::String(date.format(format).to_string())),
            Err(_) => {
                // If parsing fails, return the original value
                Ok(value.clone())
            }
        }
    }
}

/// Filter for JSON formatting
///
/// Usage: `{{ data | json }}`
pub struct JsonFilter;

impl Filter for JsonFilter {
    fn filter(&self, value: &Value, _args: &HashMap<String, Value>) -> TeraResult<Value> {
        serde_json::to_string_pretty(value)
            .map(Value::String)
            .map_err(|e| tera::Error::msg(format!("JSON error: {}", e)))
    }
}

/// Filter for compact JSON formatting
///
/// Usage: `{{ data | json_compact }}`
pub struct JsonCompactFilter;

impl Filter for JsonCompactFilter {
    fn filter(&self, value: &Value, _args: &HashMap<String, Value>) -> TeraResult<Value> {
        serde_json::to_string(value)
            .map(Value::String)
            .map_err(|e| tera::Error::msg(format!("JSON error: {}", e)))
    }
}

/// Filter for string uppercasing
///
/// Usage: `{{ text | upper }}`
pub struct UpperFilter;

impl Filter for UpperFilter {
    fn filter(&self, value: &Value, _args: &HashMap<String, Value>) -> TeraResult<Value> {
        value
            .as_str()
            .map(|s| Value::String(s.to_uppercase()))
            .ok_or_else(|| tera::Error::msg("Value must be a string"))
    }
}

/// Filter for string lowercasing
///
/// Usage: `{{ text | lower }}`
pub struct LowerFilter;

impl Filter for LowerFilter {
    fn filter(&self, value: &Value, _args: &HashMap<String, Value>) -> TeraResult<Value> {
        value
            .as_str()
            .map(|s| Value::String(s.to_lowercase()))
            .ok_or_else(|| tera::Error::msg("Value must be a string"))
    }
}

/// Register all custom filters with a Tera instance
pub fn register_filters(tera: &mut tera::Tera) {
    tera.register_filter("date", DateFormatFilter);
    tera.register_filter("json", JsonFilter);
    tera.register_filter("json_compact", JsonCompactFilter);
    tera.register_filter("upper", UpperFilter);
    tera.register_filter("lower", LowerFilter);
}
