use crate::{GCAbiConversion, GCDatapoint};
use std::slice::from_raw_parts;

/// Zero cost abstraction over the GCPluginConfig ABI struct
pub struct GCPluginConfig(gc_abi_sys::GCPluginConfig);

impl GCPluginConfig {
    /// Create a new GCPluginConfig
    ///
    /// # Safety
    /// The caller is responsible for ensuring the pointers are valid for the lifetime of the GCPluginConfig
    /// This also applies to own_datapoints and subscribed_datapoints!
    pub unsafe fn new(
        own_datapoints: *const [GCDatapoint],
        subscribed_datapoints: *const [GCDatapoint],
        callbacks: *const gc_abi_sys::sGCJsonCallbacks,
    ) -> Self {
        GCPluginConfig(gc_abi_sys::GCPluginConfig {
            ownDatapoints: own_datapoints as *const gc_abi_sys::sGCDatapoint,
            ownDatapointsCount: own_datapoints.len() as u64,
            subscribedDatapoints: subscribed_datapoints as *const gc_abi_sys::sGCDatapoint,
            subscribedDatapointsCount: subscribed_datapoints.len() as u64,
            pluginJsonConfig: callbacks,
        })
    }

    /// Get the datapoints that the plugin is allowed to publish
    pub fn get_own_datapoints(&self) -> &[GCDatapoint] {
        // Safety:
        // The pointer is guaranteed to be valid by the gateway core which also guarantees that the count is correct
        unsafe {
            let ptr_casted = self.0.ownDatapoints as *const GCDatapoint;
            from_raw_parts(ptr_casted, self.0.ownDatapointsCount as usize)
        }
    }

    /// Get the datapoints that the plugin is subscribed to
    pub fn get_subscribed_datapoints(&self) -> &[GCDatapoint] {
        // Safety:
        // The pointer is guaranteed to be valid by the gateway core which also guarantees that the count is correct
        unsafe {
            let ptr_casted = self.0.subscribedDatapoints as *const GCDatapoint;
            from_raw_parts(ptr_casted, self.0.subscribedDatapointsCount as usize)
        }
    }
}

unsafe impl GCAbiConversion for GCPluginConfig {
    type CType = gc_abi_sys::GCPluginConfig;

    fn from_c(c_type: Self::CType) -> Self {
        GCPluginConfig(c_type)
    }

    fn into_c(self) -> Self::CType {
        self.0
    }
}
