use std::rc::Rc;

use super::{
    base_impl::inherit_ptrs::BaseObjectInheritPtrs, object, objects::AnyBaseObject, ped, player,
    vehicle, BaseObjectContainer,
};
use crate::SomeResult;

mod entity;
pub use entity::{Entity, EntityRawPtr, SyncId};

mod world_object;
pub use world_object::{WorldObject, WorldObjectRawPtr};

macro_rules! extra_pool_enum {
    (@internal
        $any_name:ident,
        $name:ident,
        $raw_ptr_type:ty: [ $(
            $variant:ident,
            $container:ty,
            $wrapper:ty;
        )+ ]
    ) => {
        paste::paste! {
            #[derive(Debug)]
            pub enum $any_name { $(
                $variant($container),
            )+ }

            impl $any_name {
                #[allow(dead_code)]
                pub(crate) fn raw_ptr(&self) -> SomeResult<$raw_ptr_type> {
                    use super::inherit_ptrs::traits::*;
                    match self { $(
                        $any_name::$variant(e) => Ok(e.inherit_ptrs()?.[<$name:snake>]()),
                    )+}
                }
            }

            impl TryFrom<AnyBaseObject> for $any_name {
                type Error = anyhow::Error;
                fn try_from(value: AnyBaseObject) -> Result<Self, Self::Error> {
                    Ok(match value {
                    $(
                        AnyBaseObject::$variant(e) => $any_name::$variant(e),
                    )+
                        base_object => anyhow::bail!("cannot convert: {base_object:?} to {}", stringify!($any_name)),
                    })
                }
            }

        $(
            impl From<$container> for $any_name {
                fn from(value: $container) -> Self {
                    $any_name::$variant(value)
                }
            }

            // TODO: refactor this shit, this only needed for meta
            impl From<Rc<$wrapper>> for $any_name {
                fn from(value: Rc<$wrapper>) -> Self {
                    $any_name::$variant(BaseObjectContainer(value))
                }
            }
        )+
        }
    };

    ($name:ident, $raw_ptr_type:ty: [ $( $variant:ident, $base_object_mod:path; )+ ]) => {
        paste::paste! {
            extra_pool_enum!(@internal
                [<Any $name>],
                $name,
                $raw_ptr_type: [
                    $(
                        $variant,
                        $base_object_mod::[<$variant Container>],
                        $base_object_mod::$variant;
                    )+
                ]
            );
        }
    };
}

extra_pool_enum!(Entity, EntityRawPtr: [
    Player, player;
    Vehicle, vehicle;
    Ped, ped;
    Object, object;
]);

extra_pool_enum!(WorldObject, WorldObjectRawPtr: [
    Player, player;
    Vehicle, vehicle;
    Ped, ped;
    Object, object;
]);
