use std::ffi::CStr;
use std::pin::Pin;
use std::ptr::NonNull;
use pipewire_wrapper_proc_macro::{interface, RawWrapper, Wrapper};
use crate::core_api::context::Context;
use crate::core_api::core::events::CoreEvents;
use crate::core_api::properties::Properties;
use crate::core_api::registry::{Registry, RegistryRef};
use crate::listeners::{AddListener, OwnListeners};
use crate::spa_interface_call;
use crate::wrapper::{RawWrapper, Wrapper};
use crate::{i32_as_void_result, new_instance_raw_wrapper, raw_wrapper};
pub mod events;
pub mod info;
#[derive(RawWrapper, Debug)]
#[interface(methods=pw_sys::pw_core_methods, interface="Core")]
#[repr(transparent)]
pub struct CoreRef {
    #[raw]
    raw: pw_sys::pw_core,
}
#[derive(Wrapper, Debug)]
pub struct Core {
    #[raw_wrapper]
    ref_: NonNull<CoreRef>,
    context: std::rc::Rc<Context>,
}
impl Core {
    pub fn connect(context: &std::rc::Rc<Context>, properties: Properties) -> crate::Result<Self> {
        let ptr =
            unsafe { pw_sys::pw_context_connect(context.as_raw_ptr(), properties.into_raw(), 0) };
        Ok(Self {
            ref_: new_instance_raw_wrapper(ptr)?,
            context: context.clone(),
        })
    }
    pub fn context(&self) -> &std::rc::Rc<Context> {
        &self.context
    }
    pub fn get_registry(&self, version: u32) -> crate::Result<Registry> {
        use crate::core_api::proxy::Proxied;
        use crate::core_api::registry::restricted::RegistryBind;
        let ref_: &RegistryRef = self.as_ref().get_registry(version, 0)?;
        Ok(Registry::from_ref(self, ref_.as_proxy()))
    }
}
impl Default for Core {
    fn default() -> Self {
        Core::connect(&std::rc::Rc::new(Context::default()), Properties::default()).unwrap()
    }
}
impl Drop for Core {
    fn drop(&mut self) {
        unsafe {
            pw_sys::pw_core_disconnect(self.as_raw_ptr());
        }
    }
}
impl CoreRef {
    pub fn hello(&self, version: u32) -> crate::Result<()> {
        let result = spa_interface_call!(self, hello, version)?;
        i32_as_void_result(result)
    }
    pub fn sync(&self, id: u32, seq: i32) -> crate::Result<()> {
        let result = spa_interface_call!(self, sync, id, seq)?;
        i32_as_void_result(result)
    }
    pub fn pong(&self, id: u32, seq: i32) -> crate::Result<()> {
        let result = spa_interface_call!(self, pong, id, seq)?;
        i32_as_void_result(result)
    }
    pub fn error(
        &self,
        id: u32,
        seq: i32,
        error_code: i32,
        description: &CStr,
    ) -> crate::Result<()> {
        let result = spa_interface_call!(self, error, id, seq, error_code, description.as_ptr())?;
        i32_as_void_result(result)
    }
    fn get_registry(&self, version: u32, user_data_size: usize) -> crate::Result<&RegistryRef> {
        let ptr = spa_interface_call!(self, get_registry, version, user_data_size)?;
        raw_wrapper(ptr)
    }
    }
impl<'a> AddListener<'a> for CoreRef {
    type Events = CoreEvents<'a>;
    fn add_listener(&self, events: Pin<Box<Self::Events>>) -> Pin<Box<Self::Events>> {
        unsafe {
            spa_interface_call!(
                self,
                add_listener,
                events.hook().as_raw_ptr(),
                events.as_raw_ptr(),
                &*events as *const _ as *mut _
            )
        };
        events
    }
}