//! 编辑器到宿主 shell 的 bridge events 常量与 payload 类型。
//! dispatch 函数保留在 lib.rs 中（与信号/overlay 耦合度高）。
use serde::{Deserialize, Serialize};
use serde_json::Value;

pub(crate) const RUNTIME_NAME: &str = "8123-leptos-tiptap-runtime";
pub(crate) const RUNTIME_VERSION: &str = "1.1.0";
pub(crate) const PROTOCOL: &str = "mnote.leptos_tiptap.bridge.v1";
pub(crate) const BLOCK_DELTA_EVENT: &str = "mnote:editor:block-delta";
pub(crate) const COMMAND_EVENT: &str = "mnote:leptos-tiptap-spike:command";
pub(crate) const HEIGHT_EVENT: &str = "mnote:leptos-tiptap-spike:height";
pub(crate) const EVENT_PREFIX: &str = "mnote:leptos-tiptap-spike";
pub(crate) const READY_EVENT: &str = "mnote:leptos-tiptap-spike:ready";
pub(crate) const CHANGE_EVENT: &str = "mnote:leptos-tiptap-spike:change";
pub(crate) const STATE_EVENT: &str = "mnote:leptos-tiptap-spike:state";
pub(crate) const STATUS_EVENT: &str = "mnote:leptos-tiptap-spike:status";
pub(crate) const SELECTION_EVENT: &str = "mnote:leptos-tiptap-spike:selection";

#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct BridgeEnvelope<T>
where
    T: Serialize,
{
    pub(crate) protocol: &'static str,
    pub(crate) runtime: &'static str,
    pub(crate) version: &'static str,
    pub(crate) source: &'static str,
    pub(crate) event: &'static str,
    pub(crate) payload: T,
}

#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct BridgeSelectorsPayload {
    pub(crate) root: &'static str,
    pub(crate) stage: &'static str,
    pub(crate) editor: &'static str,
    pub(crate) toolbar: &'static str,
    pub(crate) slash_menu: &'static str,
    pub(crate) handle: &'static str,
}

#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct HostStatusPayload {
    pub(crate) document_id: Option<String>,
    pub(crate) workspace_id: Option<String>,
    pub(crate) title: String,
    pub(crate) dirty_count: u32,
    pub(crate) selected_block_index: Option<usize>,
    pub(crate) current_block_id: Option<String>,
    pub(crate) editor_focused: bool,
    pub(crate) read_only: bool,
    pub(crate) slash_open: bool,
    pub(crate) toolbar_open: bool,
}

#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ReadyPayload {
    pub(crate) runtime_name: &'static str,
    pub(crate) selectors: BridgeSelectorsPayload,
    pub(crate) supported_commands: Vec<&'static str>,
    pub(crate) supports_embedded_mode: bool,
}

#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct StatePayload {
    pub(crate) document_id: Option<String>,
    pub(crate) workspace_id: Option<String>,
    pub(crate) title: String,
    pub(crate) dirty_count: u32,
    pub(crate) selected_block_index: Option<usize>,
    pub(crate) editor_focused: bool,
    pub(crate) slash_open: bool,
    pub(crate) toolbar_open: bool,
    pub(crate) read_only: bool,
}

#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ChangeMetaPayload {
    pub(crate) dirty_count: u32,
    pub(crate) editor_focused: bool,
    pub(crate) slash_open: bool,
    pub(crate) toolbar_open: bool,
    pub(crate) selected_block_index: Option<usize>,
    pub(crate) revision: Option<i64>,
    pub(crate) conflict_detection_key: Option<String>,
    pub(crate) read_only: bool,
}

#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ChangePayload {
    pub(crate) document_id: Option<String>,
    pub(crate) workspace_id: Option<String>,
    pub(crate) title: String,
    pub(crate) content: Value,
    pub(crate) meta: ChangeMetaPayload,
}

#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct HeightPayload {
    pub(crate) height: f64,
}

#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
#[allow(dead_code)]
pub(crate) struct HostCommandEnvelope {
    pub(crate) protocol: Option<String>,
    pub(crate) runtime: Option<String>,
    pub(crate) version: Option<String>,
    pub(crate) source: Option<String>,
    pub(crate) event: Option<String>,
    pub(crate) payload: Option<HostCommandPayload>,
}

#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct RuntimePageOptions {
    pub(crate) wide_layout: Option<bool>,
    pub(crate) small_text: Option<bool>,
    pub(crate) layout_density: Option<String>,
    pub(crate) show_heading_numbers: Option<bool>,
    pub(crate) embed_default_block_id: Option<String>,
}

#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
#[allow(dead_code)]
pub(crate) struct HostCommandPayload {
    pub(crate) command: Option<String>,
    pub(crate) document_id: Option<String>,
    pub(crate) workspace_id: Option<String>,
    pub(crate) title: Option<String>,
    pub(crate) content: Option<Value>,
    pub(crate) editable: Option<bool>,
    pub(crate) page_options: Option<RuntimePageOptions>,
    pub(crate) block_id: Option<String>,
    pub(crate) block_index: Option<usize>,
    pub(crate) text: Option<String>,
    pub(crate) reference_document_id: Option<String>,
    pub(crate) reference_block_id: Option<String>,
    pub(crate) current_block_id: Option<String>,
    pub(crate) selection: Option<Value>,
    pub(crate) revision: Option<i64>,
    pub(crate) conflict_detection_key: Option<String>,
    pub(crate) read_only: Option<bool>,
}
