use std::{cell::RefCell, ptr::NonNull, rc::Rc};

use super::{base_object::BaseObject, BaseObjectContainer};
use crate::{
    meta::base_object::{normal_meta::NormalBaseObjectMeta, synced_meta::SyncedBaseObjectMeta},
    resource::Resource,
    SomeResult, VoidResult,
};

pub(crate) type BaseObjectWrapperRc<T, InheritPtrs = ()> = Rc<BaseObjectWrapper<T, InheritPtrs>>;

pub struct BaseObjectWrapper<T, InheritPtrs: Clone = ()> {
    pub(crate) value: RefCell<BaseObject<T, InheritPtrs>>,
}

impl<T, InheritPtrs: Clone> BaseObjectWrapper<T, InheritPtrs> {
    pub(crate) fn _new(
        ptr: NonNull<T>,
        base_ptr: altv_sdk::BaseObjectMutPtr,
        inherit_ptrs: InheritPtrs,
    ) -> BaseObjectContainer<T, InheritPtrs> {
        BaseObjectContainer(Rc::new(Self {
            value: RefCell::new(BaseObject {
                ptr: Some(ptr),
                base_ptr: Some(base_ptr),
                inherit_ptrs: Some(inherit_ptrs),
            }),
        }))
    }

    pub(crate) fn ptr(&self) -> SomeResult<NonNull<T>> {
        self.value.try_borrow()?.ptr()
    }

    pub(crate) fn raw_ptr(&self) -> SomeResult<*mut T> {
        self.value.try_borrow()?.raw_ptr()
    }

    pub(crate) fn internal_destroy(&self) -> VoidResult {
        Resource::with_pending_base_object_destroy_or_creation_mut(|_, _| {
            self.value.try_borrow_mut()?.internal_destroy()
        })?;
        Ok(())
    }

    pub fn id(&self) -> SomeResult<u32> {
        self.value.try_borrow()?.id()
    }
}

impl<T, InheritPtrs: Clone> NormalBaseObjectMeta<T, InheritPtrs>
    for BaseObjectWrapper<T, InheritPtrs>
{
}

impl<T, InheritPtrs: Clone> SyncedBaseObjectMeta<T, InheritPtrs>
    for BaseObjectWrapper<T, InheritPtrs>
{
}
