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

use crate::lua::LuaEnv;

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Size {
    pub width: f64,
    pub height: f64,
}

impl Size {
    pub fn new(width: f64, height: f64) -> Self {
        Size { width, height }
    }
}

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

impl UserData for Size {
    fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
        methods.add_method_mut("set_width", |_, size, width: f64| {
            size.width = width;
            Ok(())
        });
        methods.add_method_mut("set_height", |_, size, height: f64| {
            size.height = height;
            Ok(())
        });

        methods.add_method_mut("set_size", |_, size, (width, height): (f64, f64)| {
            size.width = width;
            size.height = height;
            Ok(())
        });

        methods.add_method("get_width", |_, size, ()| Ok(size.width));
        methods.add_method("get_height", |_, size, ()| Ok(size.height));
        methods.add_method("get_size", |_, size, ()| Ok((size.width, size.height)));
    }
}

pub fn add_constructor(lua: &LuaEnv) -> crate::Result<()> {
    lua.func("Size", |_, (width, height): (f64, f64)| {
        Ok(Size::new(width, height))
    })?;
    Ok(())
}
