//! IPC protocol — command dispatch and event emission.
//!
//! All communication with the TypeScript control plane goes through
//! JSON-line messages on stdin/stdout (smartrust protocol).

use serde::Deserialize;
use tokio::sync::mpsc;

/// Sender for serialized stdout output.
pub type OutTx = mpsc::UnboundedSender<String>;

/// A command received from the TypeScript control plane.
#[derive(Deserialize)]
pub struct Command {
    pub id: String,
    pub method: String,
    #[serde(default)]
    pub params: serde_json::Value,
}

/// Send a response to a command.
pub fn respond(
    tx: &OutTx,
    id: &str,
    success: bool,
    result: Option<serde_json::Value>,
    error: Option<&str>,
) {
    let mut resp = serde_json::json!({ "id": id, "success": success });
    if let Some(r) = result {
        resp["result"] = r;
    }
    if let Some(e) = error {
        resp["error"] = serde_json::Value::String(e.to_string());
    }
    let _ = tx.send(resp.to_string());
}

/// Send a success response.
pub fn respond_ok(tx: &OutTx, id: &str, result: serde_json::Value) {
    respond(tx, id, true, Some(result), None);
}

/// Send an error response.
pub fn respond_err(tx: &OutTx, id: &str, error: &str) {
    respond(tx, id, false, None, Some(error));
}

/// Emit an event to the TypeScript control plane.
pub fn emit_event(tx: &OutTx, event: &str, data: serde_json::Value) {
    let msg = serde_json::json!({ "event": event, "data": data });
    let _ = tx.send(msg.to_string());
}
