//! Versioned C-compatible ABI types shared by host and plugins.

/// Current plugin ABI version.
pub const PIXELFLOW_ABI_VERSION: u32 = 1;

/// Versioned entry symbol exported by PixelFlow plugins.
pub const PIXELFLOW_PLUGIN_ENTRY_SYMBOL: &[u8] = b"pixelflow_plugin_entry_v1\0";

/// Borrowed UTF-8 string passed across ABI calls.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct PixelflowStringView {
    /// Pointer to UTF-8 bytes.
    pub ptr: *const u8,
    /// Byte length.
    pub len: usize,
}

impl PixelflowStringView {
    /// Creates a borrowed view from a Rust string.
    #[must_use]
    pub const fn from_rust_str(value: &str) -> Self {
        Self {
            ptr: value.as_ptr(),
            len: value.len(),
        }
    }
}

/// ABI error category.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PixelflowErrorCategory {
    /// No error.
    None = 0,
    /// Plugin loading, registration, or execution failure.
    Plugin = 1,
    /// Host-side internal invariant violation.
    Internal = 2,
}

/// ABI metadata value kind.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PixelflowMetadataKind {
    /// Boolean metadata.
    Bool = 1,
    /// Integer metadata.
    Int = 2,
    /// Floating-point metadata.
    Float = 3,
    /// UTF-8 string metadata.
    String = 4,
    /// Array metadata.
    Array = 5,
    /// Rational metadata.
    Rational = 6,
    /// Binary blob metadata.
    Blob = 7,
}

/// Structured ABI status returned by plugin and host callbacks.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct PixelflowStatus {
    /// Struct size in bytes.
    pub size: u32,
    /// ABI version used by this struct.
    pub version: u32,
    /// Zero means success; non-zero means failure.
    pub status_code: i32,
    /// Structured error category.
    pub category: PixelflowErrorCategory,
    /// Stable dotted error code.
    pub error_code: PixelflowStringView,
    /// Human-readable message.
    pub message: PixelflowStringView,
    /// Reserved fields for future compatible extension.
    pub reserved: [usize; 4],
}

impl PixelflowStatus {
    /// Returns success status.
    #[must_use]
    pub const fn ok() -> Self {
        Self {
            size: std::mem::size_of::<Self>() as u32,
            version: PIXELFLOW_ABI_VERSION,
            status_code: 0,
            category: PixelflowErrorCategory::None,
            error_code: PixelflowStringView::from_rust_str(""),
            message: PixelflowStringView::from_rust_str(""),
            reserved: [0; 4],
        }
    }

    /// Returns plugin failure status with static diagnostic strings.
    #[must_use]
    pub const fn plugin_error(code: &'static str, message: &'static str) -> Self {
        Self {
            status_code: 1,
            category: PixelflowErrorCategory::Plugin,
            error_code: PixelflowStringView::from_rust_str(code),
            message: PixelflowStringView::from_rust_str(message),
            ..Self::ok()
        }
    }

    /// Returns true when status is success.
    #[must_use]
    pub const fn is_ok(self) -> bool {
        self.status_code == 0
    }
}

/// Opaque host registrar handle.
#[repr(C)]
pub struct PixelflowRegistrar {
    _private: [u8; 0],
}

/// C-compatible filter descriptor.
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct PixelflowFilterDescriptorV1 {
    /// Struct size in bytes.
    pub size: u32,
    /// ABI version used by this struct.
    pub version: u32,
    /// Stable filter name.
    pub name: PixelflowStringView,
    /// Publisher namespace.
    pub publisher: PixelflowStringView,
    /// Plugin namespace.
    pub plugin: PixelflowStringView,
    /// Reserved fields for future compatible extension.
    pub reserved: [usize; 4],
}

/// Host callback table passed to plugins.
#[repr(C)]
#[derive(Clone, Copy)]
pub struct PixelflowHostApiV1 {
    /// Struct size in bytes.
    pub size: u32,
    /// ABI version used by this struct.
    pub version: u32,
    /// Registers one filter.
    pub register_filter: unsafe extern "C" fn(
        *mut PixelflowRegistrar,
        *const PixelflowFilterDescriptorV1,
    ) -> PixelflowStatus,
    /// Registers one metadata key.
    pub register_metadata_key: unsafe extern "C" fn(
        *mut PixelflowRegistrar,
        PixelflowStringView,
        PixelflowMetadataKind,
    ) -> PixelflowStatus,
    /// Emits host log message.
    pub log: unsafe extern "C" fn(*mut PixelflowRegistrar, u32, PixelflowStringView),
    /// Reserved fields for future compatible extension.
    pub reserved: [usize; 4],
}

/// Plugin callback table filled by entry symbol.
#[repr(C)]
#[derive(Clone, Copy)]
pub struct PixelflowPluginApiV1 {
    /// Struct size in bytes.
    pub size: u32,
    /// ABI version used by this struct.
    pub version: u32,
    /// Returns stable plugin name.
    pub plugin_name: unsafe extern "C" fn() -> PixelflowStringView,
    /// Registers plugin capabilities with host.
    pub register:
        unsafe extern "C" fn(*const PixelflowHostApiV1, *mut PixelflowRegistrar) -> PixelflowStatus,
    /// Reserved fields for future compatible extension.
    pub reserved: [usize; 5],
}

/// Type of `pixelflow_plugin_entry_v1`.
pub type PixelflowPluginEntryV1 =
    unsafe extern "C" fn(*const PixelflowHostApiV1, *mut PixelflowPluginApiV1) -> PixelflowStatus;

#[cfg(test)]
mod tests {
    use std::mem::{align_of, size_of};

    use super::{PIXELFLOW_ABI_VERSION, PixelflowPluginApiV1, PixelflowStatus};

    #[test]
    fn abi_version_is_one() {
        assert_eq!(PIXELFLOW_ABI_VERSION, 1);
    }

    #[test]
    fn status_success_has_zero_code() {
        assert_eq!(PixelflowStatus::ok().status_code, 0);
    }

    #[test]
    fn plugin_api_layout_has_stable_size_and_alignment() {
        assert_eq!(size_of::<PixelflowPluginApiV1>(), 64);
        assert_eq!(align_of::<PixelflowPluginApiV1>(), 8);
    }
}
