use mlua::{FromLua, Lua, UserData, UserDataMethods};

use crate::lua::LuaEnv;
pub use crate::renderer::prelude::*;

#[derive(Debug, Clone, PartialEq, Copy)]
pub struct LineElement {
    pub start: Point,
    pub end: Point,
    pub color: Color,
    pub thickness: f64,
}

impl LineElement {
    pub fn new(start: Point, end: Point, color: Color, thickness: f64) -> Self {
        LineElement {
            start,
            end,
            color,
            thickness,
        }
    }
}

impl FromLua for LineElement {
    fn from_lua(value: mlua::Value, _: &Lua) -> mlua::Result<Self> {
        match value {
            mlua::Value::UserData(ud) => Ok(*ud.borrow::<Self>()?),
            _ => unreachable!(),
        }
    }
}

impl UserData for LineElement {
    fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
        methods.add_method_mut("set_p1", |_, line, point: Point| {
            line.start = point;
            Ok(())
        });
        methods.add_method_mut("set_p2", |_, line, point: Point| {
            line.end = point;
            Ok(())
        });
        methods.add_method_mut("set_color", |_, line, color: Color| {
            line.color = color;
            Ok(())
        });
        methods.add_method_mut("set_thickness", |_, line, thickness: f64| {
            line.thickness = thickness;
            Ok(())
        });

        methods.add_method("get_p1", |_, line, ()| Ok(line.start));
        methods.add_method("get_p2", |_, line, ()| Ok(line.end));
        methods.add_method("get_color", |_, line, ()| Ok(line.color));
        methods.add_method("get_thickness", |_, line, ()| Ok(line.thickness));
    }
}

pub fn add_constructor(lua: &LuaEnv) -> crate::Result<()> {
    lua.func("Line", |_, (start, end, color, thickness)| {
        Ok(Element::Line(LineElement::new(
            start, end, color, thickness,
        )))
    })?;
    Ok(())
}
