use std::ffi::{CStr, CString};
use std::ops::{AddAssign, SubAssign};
use std::pin::Pin;
use std::rc::Rc;
use std::sync::atomic::AtomicUsize;
use std::sync::Mutex;
use std::time::Duration;
use spa_sys::spa_support;
use crate::core_api::loop_::LoopRef;
use crate::core_api::main_loop::{MainLoop, MainLoopRef};
use crate::spa::dict::DictRef;
use crate::spa::handle::HandleRef;
use crate::spa::loop_::AsLoopRef;
use crate::spa::pod::object::param_port_config::Direction;
use crate::spa::support::SupportRef;
use crate::wrapper::{RawWrapper, Wrapper};
use crate::{error, i32_as_void_result, spa, SPA_ID_INVALID};
pub mod client;
pub mod context;
pub mod core;
pub mod device;
pub mod factory;
pub mod link;
pub mod loop_;
pub mod main_loop;
pub mod node;
pub mod permissions;
pub mod port;
pub mod properties;
pub mod proxy;
pub mod registry;
pub mod type_info;
pub const PW_ID_ANY: u32 = SPA_ID_INVALID;
static mut INSTANCES: Mutex<usize> = Mutex::new(0);
#[derive(Debug)]
pub struct PipeWire {}
impl PipeWire {
    pub fn init(args: &Vec<&CStr>) -> PipeWire {
        unsafe {
            let argc = &mut (args.len() as i32) as *mut ::std::os::raw::c_int;
            let argv = args.as_ptr() as *mut *mut *mut ::std::os::raw::c_char;
            {
                let mut instances = INSTANCES.lock().unwrap(); pw_sys::pw_init(argc, argv);
                instances.add_assign(1);
            }
        }
        PipeWire {}
    }
    pub fn debug_is_category_enabled(&self, name: &CString) -> bool {
        unsafe { pw_sys::pw_debug_is_category_enabled(name.as_ptr()) }
    }
    pub fn get_application_name(&self) -> Option<&CStr> {
        unsafe {
            pw_sys::pw_get_application_name()
                .as_ref()
                .map(|ptr| CStr::from_ptr(ptr))
        }
    }
    pub fn get_prgname(&self) -> Option<&CStr> {
        unsafe {
            pw_sys::pw_get_prgname()
                .as_ref()
                .map(|ptr| CStr::from_ptr(ptr))
        }
    }
    pub fn get_user_name(&self) -> Option<&CStr> {
        unsafe {
            pw_sys::pw_get_user_name()
                .as_ref()
                .map(|ptr| CStr::from_ptr(ptr))
        }
    }
    pub fn get_host_name(&self) -> Option<&CStr> {
        unsafe {
            pw_sys::pw_get_host_name()
                .as_ref()
                .map(|ptr| CStr::from_ptr(ptr))
        }
    }
    pub fn get_client_name(&self) -> Option<&CStr> {
        unsafe {
            pw_sys::pw_get_client_name()
                .as_ref()
                .map(|ptr| CStr::from_ptr(ptr))
        }
    }
    pub fn in_valgrind(&self) -> bool {
        unsafe { pw_sys::pw_in_valgrind() }
    }
    pub fn check_option(&self, option: &CStr, value: &CStr) -> bool {
        unsafe { pw_sys::pw_check_option(option.as_ptr(), value.as_ptr()) }
    }
    pub fn direction_reverse(direction: &Direction) -> Direction {
        Direction::from_raw(unsafe { pw_sys::pw_direction_reverse(*direction.as_raw()) })
    }
    pub fn set_domain(&self, domain: &CStr) -> crate::Result<()> {
        unsafe { i32_as_void_result(pw_sys::pw_set_domain(domain.as_ptr())) }
    }
    pub fn get_domain(&self) -> Option<&CStr> {
        unsafe {
            pw_sys::pw_get_domain()
                .as_ref()
                .map(|ptr| CStr::from_ptr(ptr))
        }
    }
    pub fn get_spa_support(&self, max_support_elements: usize) -> Vec<SupportRef> {
        let mut support_vec: Vec<SupportRef> = Vec::with_capacity(max_support_elements);
        let support_count = unsafe {
            pw_sys::pw_get_support(
                support_vec.as_mut_ptr() as *mut spa_support,
                max_support_elements as u32,
            )
        };
        support_vec.truncate(support_count as usize);
        support_vec
    }
    pub fn load_spa_handle(
        &self,
        lib: &CStr,
        factory_name: &CStr,
        info: &DictRef,
        support: Vec<SupportRef>,
    ) -> Option<&HandleRef> {
        let handle = unsafe {
            pw_sys::pw_load_spa_handle(
                lib.as_ptr(),
                factory_name.as_ptr(),
                info.as_raw_ptr(),
                support.len() as u32,
                support.as_ptr() as *const spa_sys::spa_support,
            )
        };
        unsafe { (handle as *mut HandleRef).as_ref() }
    }
    pub fn unload_spa_handle(&self, handle: &HandleRef) -> crate::Result<()> {
        unsafe { i32_as_void_result(pw_sys::pw_unload_spa_handle(handle.as_raw_ptr())) }
    }
}
impl Drop for PipeWire {
    fn drop(&mut self) {
        unsafe {
            let mut instances = INSTANCES.lock().unwrap();
            if *instances == 0 {
                pw_sys::pw_deinit();
            } else {
                instances.sub_assign(1);
            }
        }
    }
}
impl Default for PipeWire {
    fn default() -> Self {
        PipeWire::init(&Vec::default())
    }
}