//! ShowenV2 Plugin SDK
//!
//! 插件开发者使用此 SDK 编写动态插件。
//! 实现 `ShowenPlugin` trait，然后用 `export_plugin!` 宏导出。

use serde::{Deserialize, Serialize};
use std::ffi::{c_char, c_int, c_void, CString};
use std::ptr;

// ── 重新导出消息类型（与主程序共享 JSON 契约） ──

/// 描述插件元数据。
///
/// 主程序会在加载动态库后读取此结构体，用于展示插件名称、版本、平台信息，
/// 并帮助第三方开发者确认插件是否按预期被正确识别。
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PluginInfo {
    /// 插件的人类可读名称。
    pub name: String,
    /// 插件版本号，通常使用语义化版本格式。
    pub version: String,
    /// 插件用途简介，会显示给使用者或调试工具。
    pub description: String,
    /// 插件面向的平台标识，例如 `linux` 或 `cross-platform`。
    pub platform: String,
}

/// 表示一次能力自检中的单项结果。
///
/// `self_test` 返回的列表会由主程序或测试工具消费，用于判断插件声明的能力
/// 是否已经完成最基本的运行时验证。
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CapabilityTestResult {
    /// 被测试的能力名称，通常与 `ShowenPlugin::capabilities` 中的条目对应。
    pub capability: String,
    /// 该能力是否通过自检。
    pub passed: bool,
    /// 面向开发者的结果说明，可用于记录失败原因或补充上下文。
    pub message: String,
}

/// 插件系统中的标准消息信封。
///
/// 所有跨插件、插件到主程序、或插件到管理层的通信都通过此结构体完成。
/// 它定义了统一的发送者、目的地和消息载荷格式，并通过 JSON 在 ABI 边界上传输。
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Envelope {
    /// 消息发送者名称，通常填写当前插件名。
    pub from: String,
    /// 消息目标，可指定单个插件、广播或管理层。
    pub to: Destination,
    /// 实际发送的业务消息。
    pub message: Message,
}

/// 定义消息的投递目标。
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Destination {
    /// 将消息发送给指定名称的插件。
    Plugin(String),
    /// 将消息广播给所有感兴趣的接收方。
    Broadcast,
    /// 将消息发送给主程序的管理层或调度层。
    Manager,
}

/// 消息类型 — 与主程序 Message 枚举保持 JSON 兼容
/// 动态插件只需处理自己关心的消息变体
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Message {
    /// 发送给播放器模块的命令。
    ///
    /// 载荷内容由播放器插件或主程序定义，通常是 JSON 对象，包含播放、暂停、
    /// 跳转等控制信息。
    PlayerCommand(serde_json::Value),
    /// 来自播放器模块的状态快照或状态变更。
    ///
    /// 适用于同步当前曲目、播放状态、进度等信息。
    PlayerStatus(serde_json::Value),
    /// 触发器事件。
    ///
    /// `name` 表示触发器名称，`value` 表示本次触发附带的值，适合按钮、传感器
    /// 或自动化规则触发。
    Trigger {
        /// 触发器名称。
        name: String,
        /// 触发器携带的值。
        value: String,
    },
    /// 状态机切换事件。
    ///
    /// 当系统状态从一个命名状态迁移到另一个状态时使用，便于插件同步行为。
    StateChanged {
        /// 切换前的状态名。
        old_state: String,
        /// 切换后的状态名。
        new_state: String,
    },
    /// 请求屏幕锁定或解锁。
    ///
    /// `true` 表示请求锁定，`false` 表示请求解除锁定。
    ScreenLockRequest(bool),
    /// 请求显示或隐藏光标。
    ///
    /// `true` 表示显示光标，`false` 表示隐藏光标。
    CursorVisibility(bool),
    /// Wi-Fi 控制命令。
    ///
    /// 具体 JSON 字段由网络相关插件或主程序约定。
    WifiCommand(serde_json::Value),
    /// Wi-Fi 操作结果字符串。
    ///
    /// 一般用于返回简短状态、错误描述或执行结果摘要。
    WifiResult(String),
    /// Wi-Fi 配网成功事件。
    WifiProvisioned {
        /// 当前接入的 SSID。
        ssid: String,
        /// 当前设备获取到的 IP 地址。
        ip: String,
    },
    /// 配置重载完成通知。
    ///
    /// JSON 载荷通常是更新后的配置片段或完整配置。
    ConfigReloaded(serde_json::Value),
    /// 请求主程序重新加载配置。
    ConfigReloadRequest,
    /// 请求插件或主程序进入关闭流程。
    Shutdown,
    /// 插件就绪通知。
    ///
    /// 字符串内容通常为就绪插件的名称。
    PluginReady(String),
    /// 设备命令（业务插件 → DevicePlugin）。
    DeviceCommand(DeviceCommand),
    /// 设备响应（DevicePlugin → 请求者）。
    DeviceResponse(DeviceResponse),
    /// 设备事件（DevicePlugin → 广播）。
    DeviceEvent(DeviceEvent),
    /// 自定义业务消息。
    ///
    /// 当标准消息不足以表达插件间协议时，可通过 `kind` 区分消息类型，
    /// 并在 `payload` 中承载自定义内容。
    Custom {
        /// 自定义消息类型标识。
        kind: String,
        /// 自定义消息的文本载荷。
        payload: String,
    },
}

// ── 设备管理类型 ──

/// 像素格式
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum PixelFormat {
    /// RGBA 8888 格式（每像素 4 字节）
    RGBA8888,
    /// RGB 888 格式（每像素 3 字节）
    RGB888,
    /// RGB 565 格式（每像素 2 字节）
    RGB565,
}

/// 传感器类型
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum SensorType {
    /// 温度传感器
    Temperature,
    /// 湿度传感器
    Humidity,
    /// 光线传感器
    Light,
    /// 接近传感器
    Proximity,
}

/// 触摸动作
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum TouchAction {
    /// 按下
    Down,
    /// 移动
    Move,
    /// 抬起
    Up,
}

/// 设备能力
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum DeviceCapability {
    /// 显示屏
    Display,
    /// 触摸屏
    Touch,
    /// 按钮
    Buttons,
    /// 音频
    Audio,
    /// 电池
    Battery,
    /// 背光
    Backlight,
    /// 传感器
    Sensors,
    /// 帧缓冲
    Framebuffer,
    /// GPIO
    GPIO,
    /// 光标控制能力
    Cursor,
}

/// 设备命令（业务插件 → DevicePlugin）
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum DeviceCommand {
    /// 获取显示信息
    GetDisplayInfo,
    /// 设置亮度（0-100）
    SetBrightness(u8),
    /// 设置背光开关
    SetBacklight(bool),
    /// 写入帧缓冲
    WriteFramebuffer { data: Vec<u8>, format: PixelFormat },
    /// 设置防息屏
    SetSleepInhibit(bool),
    /// 设置光标可见性
    /// - true: 显示光标
    /// - false: 隐藏光标（通过 unclutter 或平台特定方式）
    SetCursorVisible(bool),
    /// 获取电池电量
    GetBatteryLevel,
    /// 设置音量（0-100）
    SetVolume(u8),
    /// 播放音频
    PlayAudio { path: String },
    /// 获取触摸事件
    GetTouchEvents,
    /// 获取按钮状态
    GetButtonState,
    /// 获取传感器数据
    GetSensorData(SensorType),
    /// 自定义命令
    CustomCommand {
        subsystem: String,
        payload: serde_json::Value,
    },
}

/// 设备响应（DevicePlugin → 请求者）
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum DeviceResponse {
    /// 显示信息
    DisplayInfo {
        width: u32,
        height: u32,
        format: PixelFormat,
    },
    /// 传感器数据
    SensorData { sensor: SensorType, value: f64 },
    /// 电池电量（0-100）
    BatteryLevel(u8),
    /// 操作成功
    Ok,
    /// 操作失败
    Error(String),
    /// 自定义响应
    Custom(serde_json::Value),
}

/// 设备事件（DevicePlugin → 广播）
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum DeviceEvent {
    /// 触摸事件
    TouchEvent { x: i32, y: i32, action: TouchAction },
    /// 按钮事件
    ButtonEvent { button: u8, pressed: bool },
    /// 电池电量低
    BatteryLow(u8),
    /// 显示器已连接
    DisplayConnected,
    /// 显示器已断开
    DisplayDisconnected,
    /// 传感器警报
    SensorAlert { sensor: SensorType, value: f64 },
}

// ── FFI 类型（与主程序 plugin_abi.rs 完全对应） ──

/// 插件实例在 FFI 边界上的不透明句柄。
pub type PluginHandle = *mut c_void;
/// 指向以 null 结尾的 C 字符串。
pub type FfiStr = *const c_char;

/// ABI 安全的字符串返回类型。
///
/// 主程序从插件取回 JSON 或错误信息时使用该结构体。内存由插件分配，
/// 再通过 `PluginVTable::free_string` 释放。
///
/// 该类型故意不携带 allocator 标识，以保持现有 `repr(C)` ABI 稳定；
/// 因此调用方必须通过 API 契约保证“谁分配，谁释放”。
///
/// # Safety
/// - 插件返回给主程序的 `FfiString` 只能由当前插件导出的
///   `PluginVTable::free_string` 释放。
/// - 主程序分配的字符串绝不能交给插件释放，反之亦然。
/// - 跨 allocator 释放会导致未定义行为（可能崩溃或内存损坏）。
#[repr(C)]
pub struct FfiString {
    /// 字符串起始指针；为空时表示没有内容。
    pub ptr: *mut c_char,
    /// 字节长度，不包含结尾的 `\0`。
    pub len: usize,
}

impl FfiString {
    /// 从 Rust `String` 构造 FFI 字符串。
    ///
    /// 如果字符串中包含内部 `NUL` 字节，会返回空字符串表示失败。
    /// 生成的指针必须由当前插件的 `free_string` 回调释放。
    pub fn from_string(s: String) -> Self {
        match CString::new(s) {
            Ok(cstr) => {
                let len = cstr.as_bytes().len();
                Self {
                    ptr: cstr.into_raw(),
                    len,
                }
            }
            Err(_) => Self::null(),
        }
    }

    /// 构造空的 FFI 字符串。
    pub fn null() -> Self {
        Self {
            ptr: ptr::null_mut(),
            len: 0,
        }
    }

    /// 复制为 Rust String（不释放底层内存）
    ///
    /// # Safety
    /// `ptr` 必须指向由当前插件 allocator 创建的有效 null-terminated C 字符串。
    /// 调用此函数不会转移所有权，原始分配方仍负责释放该内存。
    pub unsafe fn to_string(&self) -> Option<String> {
        if self.ptr.is_null() {
            return None;
        }
        unsafe { std::ffi::CStr::from_ptr(self.ptr) }
            .to_str()
            .ok()
            .map(str::to_owned)
    }
}

/// ABI 安全的返回值结构。
///
/// `code == 0` 表示成功，非零表示失败；`error` 中包含面向开发者的错误文本。
#[repr(C)]
pub struct FfiResult {
    /// 状态码，约定 `0` 为成功，`-1` 为失败。
    pub code: c_int,
    /// 错误消息；成功时通常为空字符串。
    pub error: FfiString,
}

impl FfiResult {
    /// 创建表示成功的返回值。
    pub fn ok() -> Self {
        Self {
            code: 0,
            error: FfiString::null(),
        }
    }

    /// 创建表示失败的返回值，并附带错误消息。
    pub fn err(msg: String) -> Self {
        Self {
            code: -1,
            error: FfiString::from_string(msg),
        }
    }
}

/// 主程序提供给插件的消息发送回调。
///
/// 插件通常无需直接调用该类型，而是通过 [`MessageSender`] 使用安全封装。
/// 若插件把发送器保存到后台线程，必须在 [`ShowenPlugin::stop`] 返回前终止这些线程，
/// 之后不得再继续使用该回调或 `MessageSender`。
pub type SendCallback = unsafe extern "C" fn(ctx: *mut c_void, envelope_json: FfiStr);

/// 插件导出给主程序的函数表。
///
/// 该结构与主程序中的 ABI 定义一一对应。普通插件作者一般不需要手动构造，
/// 使用 [`export_plugin!`] 宏即可自动生成。
#[repr(C)]
pub struct PluginVTable {
    /// 创建插件实例。
    pub create: unsafe extern "C" fn() -> PluginHandle,
    /// 获取 [`PluginInfo`] 的 JSON 序列化结果。
    pub get_info: unsafe extern "C" fn(handle: PluginHandle) -> FfiString,
    /// 初始化插件实例。
    pub init: unsafe extern "C" fn(
        handle: PluginHandle,
        config_json: FfiStr,
        send_ctx: *mut c_void,
        send_cb: SendCallback,
    ) -> FfiResult,
    /// 启动插件。
    pub start: unsafe extern "C" fn(handle: PluginHandle) -> FfiResult,
    /// 处理一条 JSON 序列化消息。
    pub handle_message:
        unsafe extern "C" fn(handle: PluginHandle, message_json: FfiStr) -> FfiResult,
    /// 停止插件。
    pub stop: unsafe extern "C" fn(handle: PluginHandle) -> FfiResult,
    /// 释放由插件返回的字符串。
    ///
    /// # Safety
    /// 只能释放当前插件导出的 `FfiString`。不要将宿主分配的字符串传给这里。
    pub free_string: unsafe extern "C" fn(s: FfiString),
    /// 销毁插件实例。
    pub destroy: unsafe extern "C" fn(handle: PluginHandle),
    /// 获取插件能力列表的 JSON 序列化结果。
    pub get_capabilities: unsafe extern "C" fn(handle: PluginHandle) -> FfiString,
    /// 获取插件自检结果列表的 JSON 序列化结果。
    pub self_test: unsafe extern "C" fn(handle: PluginHandle) -> FfiString,
}

// ── 高级接口：插件作者实现此 trait ──

/// 消息发送器，封装底层 FFI 回调并提供安全的 Rust API。
///
/// 插件在 [`ShowenPlugin::init`] 中会收到一个 `MessageSender`，之后可将其保存到
/// 插件状态中，供运行期间向其他插件或主程序发送消息。
pub struct MessageSender {
    ctx: *mut c_void,
    cb: SendCallback,
}

impl MessageSender {
    /// 基于底层发送上下文和回调创建发送器。
    ///
    /// 普通插件作者通常不需要手动调用该方法；主程序在初始化插件时会自动构造。
    ///
    /// # Examples
    /// ```ignore
    /// use showen_plugin_sdk::{MessageSender, SendCallback};
    /// use std::ffi::c_void;
    ///
    /// unsafe extern "C" fn callback(_: *mut c_void, _: *const std::ffi::c_char) {}
    ///
    /// let sender = MessageSender::new(std::ptr::null_mut(), callback as SendCallback);
    /// # let _ = sender;
    /// ```
    pub fn new(ctx: *mut c_void, cb: SendCallback) -> Self {
        Self { ctx, cb }
    }

    /// 发送完整的消息信封。
    ///
    /// 当你已经手动构造好 [`Envelope`]，或者需要完全控制发送者、目标和消息载荷时，
    /// 直接使用此方法最合适。
    ///
    /// # Examples
    /// ```ignore
    /// use showen_plugin_sdk::{Destination, Envelope, Message, MessageSender};
    ///
    /// # let sender: MessageSender = unimplemented!();
    /// sender.send(&Envelope {
    ///     from: "clock".to_string(),
    ///     to: Destination::Manager,
    ///     message: Message::PluginReady("clock".to_string()),
    /// });
    /// ```
    pub fn send(&self, envelope: &Envelope) {
        if let Ok(json) = serde_json::to_string(envelope) {
            if let Ok(cstr) = CString::new(json) {
                unsafe { (self.cb)(self.ctx, cstr.as_ptr()) };
            }
        }
    }

    /// 发送消息给指定插件。
    ///
    /// 这是构造 [`Destination::Plugin`] 的便捷方法，适合点对点通信。
    ///
    /// # Examples
    /// ```ignore
    /// use showen_plugin_sdk::{Message, MessageSender};
    ///
    /// # let sender: MessageSender = unimplemented!();
    /// sender.send_to(
    ///     "clock",
    ///     "player",
    ///     Message::Custom {
    ///         kind: "sync-request".to_string(),
    ///         payload: "{}".to_string(),
    ///     },
    /// );
    /// ```
    pub fn send_to(&self, from: &str, to_plugin: &str, message: Message) {
        self.send(&Envelope {
            from: from.to_string(),
            to: Destination::Plugin(to_plugin.to_string()),
            message,
        });
    }

    /// 广播消息给所有接收方。
    ///
    /// 适合发送系统事件、状态变更或多个插件都可能关心的通知。
    ///
    /// # Examples
    /// ```ignore
    /// use showen_plugin_sdk::{Message, MessageSender};
    ///
    /// # let sender: MessageSender = unimplemented!();
    /// sender.broadcast(
    ///     "video",
    ///     Message::StateChanged {
    ///         old_state: "idle".to_string(),
    ///         new_state: "playing".to_string(),
    ///     },
    /// );
    /// ```
    ///
    /// # 注意：Phase 2 占位消息
    /// 以下消息变体当前在核心代码中**无生产者**，仅作为 Phase 2 占位保留。
    /// 插件开发者不应在 `handle_message` 中为其编写业务逻辑（写了也不会被触发），
    /// 也不应主动广播它们（核心不消费）：
    /// - `Message::WifiProvisioned` — WiFi 配网完成事件（待 WiFi 插件补生产者）
    /// - `Message::DeviceEvent` — 设备事件上报通道（待 DeviceBackend trait 扩展）
    /// - `Message::CursorVisibility` — 光标可见性（实际链路已改走
    ///   `DeviceCommand::SetCursorVisible`，此变体仅为向后兼容保留）
    pub fn broadcast(&self, from: &str, message: Message) {
        self.send(&Envelope {
            from: from.to_string(),
            to: Destination::Broadcast,
            message,
        });
    }

    /// 发送消息给主程序管理层。
    ///
    /// 适用于请求重载配置、上报就绪状态、或提交不属于单个插件的系统级事件。
    ///
    /// # Examples
    /// ```ignore
    /// use showen_plugin_sdk::{Message, MessageSender};
    ///
    /// # let sender: MessageSender = unimplemented!();
    /// sender.send_to_manager(
    ///     "config-watcher",
    ///     Message::ConfigReloadRequest,
    /// );
    /// ```
    pub fn send_to_manager(&self, from: &str, message: Message) {
        self.send(&Envelope {
            from: from.to_string(),
            to: Destination::Manager,
            message,
        });
    }
}

// SendCallback 是 extern "C" fn 指针，可跨线程安全传递
unsafe impl Send for MessageSender {}
unsafe impl Sync for MessageSender {}

/// 动态插件的高层 Rust 接口。
///
/// 第三方插件作者只需要实现此 trait，再调用 [`export_plugin!`] 宏，即可导出一个
/// 可被主程序加载的动态库。主程序会按照 `info -> init -> start -> handle_message -> stop`
/// 的生命周期驱动插件。
pub trait ShowenPlugin: Send {
    /// 返回插件的静态元信息。
    ///
    /// 主程序会在插件加载后尽早调用此方法，用于识别插件、展示描述并进行兼容性判断。
    ///
    /// # Examples
    /// ```ignore
    /// use showen_plugin_sdk::{PluginInfo, ShowenPlugin};
    ///
    /// struct DemoPlugin;
    ///
    /// impl ShowenPlugin for DemoPlugin {
    ///     fn info(&self) -> PluginInfo {
    ///         PluginInfo {
    ///             name: "demo".to_string(),
    ///             version: "0.1.0".to_string(),
    ///             description: "Example plugin".to_string(),
    ///             platform: "linux".to_string(),
    ///         }
    ///     }
    ///
    ///     fn init(&mut self, _: &str, _: showen_plugin_sdk::MessageSender) -> Result<(), String> { Ok(()) }
    ///     fn start(&mut self) -> Result<(), String> { Ok(()) }
    ///     fn handle_message(&mut self, _: showen_plugin_sdk::Message) -> Result<(), String> { Ok(()) }
    ///     fn stop(&mut self) -> Result<(), String> { Ok(()) }
    /// }
    /// ```
    fn info(&self) -> PluginInfo;

    /// 声明插件支持的能力列表。
    ///
    /// 能力字符串通常用于主程序展示、诊断以及自测分组。默认实现返回空列表。
    ///
    /// # Examples
    /// ```ignore
    /// # use showen_plugin_sdk::{PluginInfo, ShowenPlugin};
    /// # struct DemoPlugin;
    /// # impl ShowenPlugin for DemoPlugin {
    /// #     fn info(&self) -> PluginInfo {
    /// #         PluginInfo { name: "demo".into(), version: "0.1.0".into(), description: "Example".into(), platform: "linux".into() }
    /// #     }
    ///     fn capabilities(&self) -> Vec<String> {
    ///         vec!["wifi.scan".to_string(), "wifi.connect".to_string()]
    ///     }
    /// #     fn init(&mut self, _: &str, _: showen_plugin_sdk::MessageSender) -> Result<(), String> { Ok(()) }
    /// #     fn start(&mut self) -> Result<(), String> { Ok(()) }
    /// #     fn handle_message(&mut self, _: showen_plugin_sdk::Message) -> Result<(), String> { Ok(()) }
    /// #     fn stop(&mut self) -> Result<(), String> { Ok(()) }
    /// # }
    /// ```
    fn capabilities(&self) -> Vec<String> {
        vec![]
    }

    /// 运行插件自测，返回每项能力的测试结果。
    ///
    /// 默认实现会把 `capabilities` 返回的每个能力都标记为通过，并给出
    /// `"no test defined"` 提示。若插件依赖外部设备、系统命令或网络状态，建议覆写此方法。
    ///
    /// # Examples
    /// ```ignore
    /// # use showen_plugin_sdk::{CapabilityTestResult, PluginInfo, ShowenPlugin};
    /// # struct DemoPlugin;
    /// # impl ShowenPlugin for DemoPlugin {
    /// #     fn info(&self) -> PluginInfo {
    /// #         PluginInfo { name: "demo".into(), version: "0.1.0".into(), description: "Example".into(), platform: "linux".into() }
    /// #     }
    ///     fn self_test(&mut self) -> Vec<CapabilityTestResult> {
    ///         vec![CapabilityTestResult {
    ///             capability: "wifi.scan".to_string(),
    ///             passed: true,
    ///             message: "scan backend reachable".to_string(),
    ///         }]
    ///     }
    /// #     fn init(&mut self, _: &str, _: showen_plugin_sdk::MessageSender) -> Result<(), String> { Ok(()) }
    /// #     fn start(&mut self) -> Result<(), String> { Ok(()) }
    /// #     fn handle_message(&mut self, _: showen_plugin_sdk::Message) -> Result<(), String> { Ok(()) }
    /// #     fn stop(&mut self) -> Result<(), String> { Ok(()) }
    /// # }
    /// ```
    fn self_test(&mut self) -> Vec<CapabilityTestResult> {
        self.capabilities()
            .into_iter()
            .map(|c| CapabilityTestResult {
                capability: c,
                passed: true,
                message: "no test defined".into(),
            })
            .collect()
    }

    /// 初始化插件。
    ///
    /// 主程序会把插件配置的 JSON 文本和一个 [`MessageSender`] 传入。插件通常在此阶段
    /// 解析配置、保存发送器、准备运行所需资源，但不应启动长期运行任务。
    ///
    /// # Examples
    /// ```ignore
    /// # use showen_plugin_sdk::{MessageSender, PluginInfo, ShowenPlugin};
    /// # struct DemoPlugin {
    /// #     sender: Option<MessageSender>,
    /// # }
    /// # impl ShowenPlugin for DemoPlugin {
    /// #     fn info(&self) -> PluginInfo {
    /// #         PluginInfo { name: "demo".into(), version: "0.1.0".into(), description: "Example".into(), platform: "linux".into() }
    /// #     }
    ///     fn init(&mut self, config_json: &str, sender: MessageSender) -> Result<(), String> {
    ///         let _config: serde_json::Value =
    ///             serde_json::from_str(config_json).map_err(|e| e.to_string())?;
    ///         self.sender = Some(sender);
    ///         Ok(())
    ///     }
    /// #     fn start(&mut self) -> Result<(), String> { Ok(()) }
    /// #     fn handle_message(&mut self, _: showen_plugin_sdk::Message) -> Result<(), String> { Ok(()) }
    /// #     fn stop(&mut self) -> Result<(), String> { Ok(()) }
    /// # }
    /// ```
    fn init(&mut self, config_json: &str, sender: MessageSender) -> Result<(), String>;

    /// 启动插件。
    ///
    /// 在 `init` 成功之后调用。适合在这里启动后台线程、注册监听器或发送
    /// [`Message::PluginReady`] 等就绪通知。
    ///
    /// # Examples
    /// ```ignore
    /// # use showen_plugin_sdk::{Message, MessageSender, PluginInfo, ShowenPlugin};
    /// # struct DemoPlugin {
    /// #     sender: Option<MessageSender>,
    /// # }
    /// # impl ShowenPlugin for DemoPlugin {
    /// #     fn info(&self) -> PluginInfo {
    /// #         PluginInfo { name: "demo".into(), version: "0.1.0".into(), description: "Example".into(), platform: "linux".into() }
    /// #     }
    /// #     fn init(&mut self, _: &str, sender: MessageSender) -> Result<(), String> { self.sender = Some(sender); Ok(()) }
    ///     fn start(&mut self) -> Result<(), String> {
    ///         if let Some(sender) = &self.sender {
    ///             sender.send_to_manager("demo", Message::PluginReady("demo".to_string()));
    ///         }
    ///         Ok(())
    ///     }
    /// #     fn handle_message(&mut self, _: showen_plugin_sdk::Message) -> Result<(), String> { Ok(()) }
    /// #     fn stop(&mut self) -> Result<(), String> { Ok(()) }
    /// # }
    /// ```
    fn start(&mut self) -> Result<(), String>;

    /// 处理主程序转发给插件的消息。
    ///
    /// 进入此方法前，JSON 已经被 SDK 反序列化为 [`Message`]。插件应只匹配自己关心的
    /// 消息变体，并在必要时返回错误字符串帮助定位问题。
    ///
    /// # Examples
    /// ```ignore
    /// # use showen_plugin_sdk::{Message, PluginInfo, ShowenPlugin};
    /// # struct DemoPlugin;
    /// # impl ShowenPlugin for DemoPlugin {
    /// #     fn info(&self) -> PluginInfo {
    /// #         PluginInfo { name: "demo".into(), version: "0.1.0".into(), description: "Example".into(), platform: "linux".into() }
    /// #     }
    /// #     fn init(&mut self, _: &str, _: showen_plugin_sdk::MessageSender) -> Result<(), String> { Ok(()) }
    /// #     fn start(&mut self) -> Result<(), String> { Ok(()) }
    ///     fn handle_message(&mut self, message: Message) -> Result<(), String> {
    ///         match message {
    ///             Message::Shutdown => Ok(()),
    ///             Message::Custom { kind, payload } if kind == "sync" => {
    ///                 let _ = payload;
    ///                 Ok(())
    ///             }
    ///             _ => Ok(()),
    ///         }
    ///     }
    /// #     fn stop(&mut self) -> Result<(), String> { Ok(()) }
    /// # }
    /// ```
    fn handle_message(&mut self, message: Message) -> Result<(), String>;

    /// 停止插件并释放运行期资源。
    ///
    /// 该方法通常用于停止后台线程、撤销监听、关闭文件句柄或网络连接。执行完成后，
    /// 主程序可能很快销毁插件实例。所有后台线程必须在该方法返回前退出，并停止使用
    /// 之前在 `init` 中收到的 `MessageSender`。
    ///
    /// # Examples
    /// ```ignore
    /// # use showen_plugin_sdk::{PluginInfo, ShowenPlugin};
    /// # struct DemoPlugin {
    /// #     running: bool,
    /// # }
    /// # impl ShowenPlugin for DemoPlugin {
    /// #     fn info(&self) -> PluginInfo {
    /// #         PluginInfo { name: "demo".into(), version: "0.1.0".into(), description: "Example".into(), platform: "linux".into() }
    /// #     }
    /// #     fn init(&mut self, _: &str, _: showen_plugin_sdk::MessageSender) -> Result<(), String> { Ok(()) }
    /// #     fn start(&mut self) -> Result<(), String> { self.running = true; Ok(()) }
    /// #     fn handle_message(&mut self, _: showen_plugin_sdk::Message) -> Result<(), String> { Ok(()) }
    ///     fn stop(&mut self) -> Result<(), String> {
    ///         self.running = false;
    ///         Ok(())
    ///     }
    /// # }
    /// ```
    fn stop(&mut self) -> Result<(), String>;
}

// ── 导出宏：自动生成 extern "C" 胶水代码 ──

/// 将 [`ShowenPlugin`] 实现导出为主程序可加载的 C ABI 入口。
///
/// 该宏会自动生成完整的 `extern "C"` 胶水代码，包括：
///
/// - 创建与销毁插件实例
/// - 把 `PluginInfo`、capabilities、自测结果序列化为 JSON
/// - 在 ABI 边界上捕获 panic，避免传播到主程序
/// - 把传入的 JSON 消息反序列化为 [`Message`] 后再调用 trait 方法
/// - 导出主程序约定名称的 `showen_plugin_vtable`
///
/// 传入参数：
///
/// - 第一个参数是插件具体类型
/// - 第二个参数是无参构造表达式，例如 `MyPlugin::new()`
///
/// 使用此宏时，插件类型必须实现 [`ShowenPlugin`]，且构造表达式应返回该类型实例。
///
/// # Examples
/// ```ignore
/// use showen_plugin_sdk::{
///     export_plugin, Message, MessageSender, PluginInfo, ShowenPlugin,
/// };
///
/// struct MyPlugin {
///     sender: Option<MessageSender>,
/// }
///
/// impl MyPlugin {
///     fn new() -> Self {
///         Self { sender: None }
///     }
/// }
///
/// impl ShowenPlugin for MyPlugin {
///     fn info(&self) -> PluginInfo {
///         PluginInfo {
///             name: "my-plugin".to_string(),
///             version: "0.1.0".to_string(),
///             description: "Example ShowenV2 plugin".to_string(),
///             platform: "linux".to_string(),
///         }
///     }
///
///     fn init(&mut self, _config_json: &str, sender: MessageSender) -> Result<(), String> {
///         self.sender = Some(sender);
///         Ok(())
///     }
///
///     fn start(&mut self) -> Result<(), String> {
///         if let Some(sender) = &self.sender {
///             sender.send_to_manager(
///                 "my-plugin",
///                 Message::PluginReady("my-plugin".to_string()),
///             );
///         }
///         Ok(())
///     }
///
///     fn handle_message(&mut self, _message: Message) -> Result<(), String> {
///         Ok(())
///     }
///
///     fn stop(&mut self) -> Result<(), String> {
///         Ok(())
///     }
/// }
///
/// export_plugin!(MyPlugin, MyPlugin::new());
/// ```
///
/// 生成的 `showen_plugin_vtable` 会被主程序在加载动态库后自动发现，因此插件 crate
/// 通常只需在 `lib.rs` 末尾调用一次该宏。
#[macro_export]
macro_rules! export_plugin {
    ($plugin_type:ty, $constructor:expr) => {
        fn __showen_panic_error(payload: Box<dyn std::any::Any + Send>) -> String {
            let msg = if let Some(s) = payload.downcast_ref::<&'static str>() {
                (*s).to_string()
            } else if let Some(s) = payload.downcast_ref::<String>() {
                s.clone()
            } else {
                "unknown panic".to_string()
            };
            format!("plugin panicked: {}", msg)
        }

        unsafe extern "C" fn __showen_create() -> $crate::PluginHandle {
            match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
                let plugin: Box<$plugin_type> = Box::new($constructor);
                Box::into_raw(plugin) as $crate::PluginHandle
            })) {
                Ok(handle) => handle,
                Err(_) => std::ptr::null_mut(),
            }
        }

        unsafe extern "C" fn __showen_get_info(handle: $crate::PluginHandle) -> $crate::FfiString {
            match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
                let plugin = unsafe { &*(handle as *const $plugin_type) };
                let info = <$plugin_type as $crate::ShowenPlugin>::info(plugin);
                match serde_json::to_string(&info) {
                    Ok(json) => $crate::FfiString::from_string(json),
                    Err(_) => $crate::FfiString::null(),
                }
            })) {
                Ok(info) => info,
                Err(_) => $crate::FfiString::null(),
            }
        }

        unsafe extern "C" fn __showen_init(
            handle: $crate::PluginHandle,
            config_json: $crate::FfiStr,
            send_ctx: *mut std::ffi::c_void,
            send_cb: $crate::SendCallback,
        ) -> $crate::FfiResult {
            match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
                let plugin = unsafe { &mut *(handle as *mut $plugin_type) };
                let config = match unsafe { std::ffi::CStr::from_ptr(config_json) }.to_str() {
                    Ok(s) => s,
                    Err(e) => return $crate::FfiResult::err(format!("invalid config UTF-8: {e}")),
                };
                let sender = $crate::MessageSender::new(send_ctx, send_cb);
                match <$plugin_type as $crate::ShowenPlugin>::init(plugin, config, sender) {
                    Ok(()) => $crate::FfiResult::ok(),
                    Err(e) => $crate::FfiResult::err(e),
                }
            })) {
                Ok(result) => result,
                Err(payload) => $crate::FfiResult::err(__showen_panic_error(payload)),
            }
        }

        unsafe extern "C" fn __showen_start(handle: $crate::PluginHandle) -> $crate::FfiResult {
            match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
                let plugin = unsafe { &mut *(handle as *mut $plugin_type) };
                match <$plugin_type as $crate::ShowenPlugin>::start(plugin) {
                    Ok(()) => $crate::FfiResult::ok(),
                    Err(e) => $crate::FfiResult::err(e),
                }
            })) {
                Ok(result) => result,
                Err(payload) => $crate::FfiResult::err(__showen_panic_error(payload)),
            }
        }

        unsafe extern "C" fn __showen_handle_message(
            handle: $crate::PluginHandle,
            message_json: $crate::FfiStr,
        ) -> $crate::FfiResult {
            match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
                let plugin = unsafe { &mut *(handle as *mut $plugin_type) };
                let json_str = match unsafe { std::ffi::CStr::from_ptr(message_json) }.to_str() {
                    Ok(s) => s,
                    Err(e) => return $crate::FfiResult::err(format!("invalid message UTF-8: {e}")),
                };
                let message: $crate::Message = match serde_json::from_str(json_str) {
                    Ok(m) => m,
                    Err(e) => return $crate::FfiResult::err(format!("invalid message JSON: {e}")),
                };
                match <$plugin_type as $crate::ShowenPlugin>::handle_message(plugin, message) {
                    Ok(()) => $crate::FfiResult::ok(),
                    Err(e) => $crate::FfiResult::err(e),
                }
            })) {
                Ok(result) => result,
                Err(payload) => $crate::FfiResult::err(__showen_panic_error(payload)),
            }
        }

        unsafe extern "C" fn __showen_stop(handle: $crate::PluginHandle) -> $crate::FfiResult {
            match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
                let plugin = unsafe { &mut *(handle as *mut $plugin_type) };
                match <$plugin_type as $crate::ShowenPlugin>::stop(plugin) {
                    Ok(()) => $crate::FfiResult::ok(),
                    Err(e) => $crate::FfiResult::err(e),
                }
            })) {
                Ok(result) => result,
                Err(payload) => $crate::FfiResult::err(__showen_panic_error(payload)),
            }
        }

        unsafe extern "C" fn __showen_destroy(handle: $crate::PluginHandle) {
            if let Ok(()) = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
                if !handle.is_null() {
                    drop(unsafe { Box::from_raw(handle as *mut $plugin_type) });
                }
            })) {
                let _ = ();
            }
        }

        unsafe extern "C" fn __showen_free_string(s: $crate::FfiString) {
            if !s.ptr.is_null() {
                drop(unsafe { std::ffi::CString::from_raw(s.ptr) });
            }
        }

        unsafe extern "C" fn __showen_get_capabilities(
            handle: $crate::PluginHandle,
        ) -> $crate::FfiString {
            match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
                let plugin = unsafe { &*(handle as *const $plugin_type) };
                let caps = <$plugin_type as $crate::ShowenPlugin>::capabilities(plugin);
                match serde_json::to_string(&caps) {
                    Ok(json) => $crate::FfiString::from_string(json),
                    Err(_) => $crate::FfiString::from_string("[]".to_string()),
                }
            })) {
                Ok(caps) => caps,
                Err(_) => $crate::FfiString::null(),
            }
        }

        unsafe extern "C" fn __showen_self_test(handle: $crate::PluginHandle) -> $crate::FfiString {
            match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
                let plugin = unsafe { &mut *(handle as *mut $plugin_type) };
                let results = <$plugin_type as $crate::ShowenPlugin>::self_test(plugin);
                match serde_json::to_string(&results) {
                    Ok(json) => $crate::FfiString::from_string(json),
                    Err(_) => $crate::FfiString::from_string("[]".to_string()),
                }
            })) {
                Ok(results) => results,
                Err(_) => $crate::FfiString::null(),
            }
        }

        #[no_mangle]
        pub static showen_plugin_vtable: $crate::PluginVTable = $crate::PluginVTable {
            create: __showen_create,
            get_info: __showen_get_info,
            init: __showen_init,
            start: __showen_start,
            handle_message: __showen_handle_message,
            stop: __showen_stop,
            free_string: __showen_free_string,
            destroy: __showen_destroy,
            get_capabilities: __showen_get_capabilities,
            self_test: __showen_self_test,
        };
    };
}
