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

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

#[derive(Debug, Clone, PartialEq, Copy)]
pub struct CircleElement {
    pub center: Point,
    pub radius: f64,
    pub color: Color,
    pub filled: bool,
    pub border_thickness: f64,
}

impl CircleElement {
    pub fn new(
        center: Point,
        radius: f64,
        color: Color,
        filled: bool,
        border_thickness: f64,
    ) -> Self {
        CircleElement {
            center,
            radius,
            color,
            filled,
            border_thickness,
        }
    }
}

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

impl UserData for CircleElement {
    fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
        methods.add_method_mut("set_center", |_, circle, point: Point| {
            circle.center = point;
            Ok(())
        });
        methods.add_method_mut("set_radius", |_, circle, radius: f64| {
            circle.radius = radius;
            Ok(())
        });
        methods.add_method_mut("set_color", |_, circle, color: Color| {
            circle.color = color;
            Ok(())
        });
        methods.add_method_mut("set_filled", |_, circle, filled: bool| {
            circle.filled = filled;
            Ok(())
        });
        methods.add_method_mut(
            "set_border_thickness",
            |_, circle, border_thickness: f64| {
                circle.border_thickness = border_thickness;
                Ok(())
            },
        );

        methods.add_method("get_center", |_, circle, ()| Ok(circle.center));
        methods.add_method("get_radius", |_, circle, ()| Ok(circle.radius));
        methods.add_method("get_color", |_, circle, ()| Ok(circle.color));
        methods.add_method("get_filled", |_, circle, ()| Ok(circle.filled));
        methods.add_method("get_border_thickness", |_, circle, ()| {
            Ok(circle.border_thickness)
        });
    }
}

pub fn add_constructor(lua: &LuaEnv) -> crate::Result<()> {
    lua.func("Circle", |_, (center, radius, color)| {
        Ok(Element::Circle(CircleElement::new(
            center, radius, color, true, 0.,
        )))
    })?;
    lua.func(
        "CircleOutline",
        |_, (center, radius, color, border_thickness)| {
            Ok(Element::Circle(CircleElement::new(
                center,
                radius,
                color,
                false,
                border_thickness,
            )))
        },
    )?;
    Ok(())
}
