use mlua::prelude::*;
use super::super::{Event, LogEvent, Metric};
use super::metric::LuaMetric;
pub struct LuaEvent {
    pub event: Event,
    pub metric_multi_value_tags: bool,
}
impl IntoLua for LuaEvent {
    #![allow(clippy::wrong_self_convention)] fn into_lua(self, lua: &Lua) -> LuaResult<LuaValue> {
        let table = lua.create_table()?;
        match self.event {
            Event::Log(log) => table.raw_set("log", log.into_lua(lua)?)?,
            Event::Metric(metric) => table.raw_set(
                "metric",
                LuaMetric {
                    metric,
                    multi_value_tags: self.metric_multi_value_tags,
                }
                .into_lua(lua)?,
            )?,
            Event::Trace(_) => {
                return Err(LuaError::ToLuaConversionError {
                    from: String::from("Event"),
                    to: "table",
                    message: Some("Trace are not supported".to_string()),
                })
            }
        }
        Ok(LuaValue::Table(table))
    }
}
impl FromLua for Event {
    fn from_lua(value: LuaValue, lua: &Lua) -> LuaResult<Self> {
        let LuaValue::Table(table) = &value else {
            return Err(LuaError::FromLuaConversionError {
                from: value.type_name(),
                to: String::from("Event"),
                message: Some("Event should be a Lua table".to_string()),
            });
        };
        match (table.raw_get("log")?, table.raw_get("metric")?) {
            (LuaValue::Table(log), LuaValue::Nil) => {
                Ok(Event::Log(LogEvent::from_lua(LuaValue::Table(log), lua)?))
            }
            (LuaValue::Nil, LuaValue::Table(metric)) => Ok(Event::Metric(Metric::from_lua(
                LuaValue::Table(metric),
                lua,
            )?)),
            _ => Err(LuaError::FromLuaConversionError {
                from: value.type_name(),
                to: String::from("Event"),
                message: Some(
                    "Event should contain either \"log\" or \"metric\" key at the top level"
                        .to_string(),
                ),
            }),
        }
    }
}
#[cfg(test)]
mod test {
    use super::*;
    use crate::event::{
        metric::{MetricKind, MetricValue},
        Metric, Value,
    };
    fn assert_event(event: Event, assertions: Vec<&'static str>) {
        let lua = Lua::new();
        lua.globals()
            .set(
                "event",
                LuaEvent {
                    event,
                    metric_multi_value_tags: false,
                },
            )
            .unwrap();
        for assertion in assertions {
            assert!(
                lua.load(assertion).eval::<bool>().expect(assertion),
                "{}",
                assertion
            );
        }
    }
    #[test]
    fn into_lua_log() {
        let mut event = LogEvent::default();
        event.insert("field", "value");
        let assertions = vec![
            "type(event) == 'table'",
            "event.metric == nil",
            "type(event.log) == 'table'",
            "event.log.field == 'value'",
        ];
        assert_event(event.into(), assertions);
    }
    #[test]
    fn into_lua_metric() {
        let event = Event::Metric(Metric::new(
            "example counter",
            MetricKind::Absolute,
            MetricValue::Counter {
                value: 0.577_215_66,
            },
        ));
        let assertions = vec![
            "type(event) == 'table'",
            "event.log == nil",
            "type(event.metric) == 'table'",
            "event.metric.name == 'example counter'",
            "event.metric.counter.value == 0.57721566",
        ];
        assert_event(event, assertions);
    }
    #[test]
    fn from_lua_log() {
        let lua_event = r#"
        {
            log = {
                field = "example",
                nested = {
                    field = "another example"
                }
            }
        }"#;
        let event = Lua::new().load(lua_event).eval::<Event>().unwrap();
        let log = event.as_log();
        assert_eq!(log["field"], Value::Bytes("example".into()));
        assert_eq!(log["nested.field"], Value::Bytes("another example".into()));
    }
    #[test]
    fn from_lua_metric() {
        let lua_event = r#"
        {
            metric = {
                name = "example counter",
                counter = {
                    value = 0.57721566
                }
            }
        }"#;
        let expected = Event::Metric(Metric::new(
            "example counter",
            MetricKind::Absolute,
            MetricValue::Counter {
                value: 0.577_215_66,
            },
        ));
        let event = Lua::new().load(lua_event).eval::<Event>().unwrap();
        vector_common::assert_event_data_eq!(event, expected);
    }
    #[test]
    #[allow(clippy::should_panic_without_expect)]
    #[should_panic]
    fn from_lua_missing_log_and_metric() {
        let lua_event = r"{
            some_field: {}
        }";
        Lua::new().load(lua_event).eval::<Event>().unwrap();
    }
}