use js_sys::Array;
use wasm_bindgen::{prelude::*, JsCast};
use crate::{
    constants::EffectType,
    objects::{Room, RoomPosition},
    prelude::*,
    Position,
};
#[wasm_bindgen]
extern "C" {
    #[derive(Clone, Debug)]
    pub type RoomObject;
    #[wasm_bindgen(method, getter = effects)]
    fn effects_internal(this: &RoomObject) -> Option<Array>;
    #[wasm_bindgen(method, getter)]
    pub fn pos(this: &RoomObject) -> RoomPosition;
    #[wasm_bindgen(method, getter)]
    pub fn room(this: &RoomObject) -> Option<Room>;
}
#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen]
    #[derive(Debug)]
    pub type Effect;
    #[wasm_bindgen(method, getter)]
    pub fn effect(this: &Effect) -> EffectType;
    #[wasm_bindgen(method, getter)]
    pub fn level(this: &Effect) -> Option<u8>;
    #[wasm_bindgen(method, getter = ticksRemaining)]
    pub fn ticks_remaining(this: &Effect) -> EffectType;
}
impl<T> HasPosition for T
where
    T: AsRef<RoomObject>,
{
    fn pos(&self) -> Position {
        RoomObject::pos(self.as_ref()).into()
    }
}
impl<T> RoomObjectProperties for T
where
    T: AsRef<RoomObject>,
{
    fn effects(&self) -> Vec<Effect> {
        RoomObject::effects_internal(self.as_ref())
            .map(|arr| arr.iter().map(JsCast::unchecked_into).collect())
            .unwrap_or_else(Vec::new)
    }
    fn effects_raw(&self) -> Option<Array> {
        RoomObject::effects_internal(self.as_ref())
    }
    fn room(&self) -> Option<Room> {
        RoomObject::room(self.as_ref())
    }
}