use chrono::Utc;
use serde_json::{json, Value};

/// Emit an NDJSON event to stdout.
pub fn emit_event(event_type: &str, target: Option<&str>, sequence: u64, data: Option<Value>) {
    let mut obj = json!({
        "event": event_type,
        "timestamp": timestamp(),
        "sequence": sequence,
    });

    if let Some(t) = target {
        obj["target"] = json!(t);
    }
    if let Some(d) = data {
        obj["data"] = d;
    }

    println!("{}", serde_json::to_string(&obj).unwrap_or_default());
}

/// Emit a change event with a diff payload.
pub fn emit_change(target: &str, sequence: u64, changes: Value) {
    let obj = json!({
        "event": "change",
        "target": target,
        "timestamp": timestamp(),
        "sequence": sequence,
        "changes": changes,
    });
    println!("{}", serde_json::to_string(&obj).unwrap_or_default());
}

/// Emit a heartbeat event (no data changed).
pub fn emit_heartbeat(sequence: u64) {
    let obj = json!({
        "event": "heartbeat",
        "timestamp": timestamp(),
        "sequence": sequence,
    });
    println!("{}", serde_json::to_string(&obj).unwrap_or_default());
}

/// Emit an error event.
pub fn emit_error(sequence: u64, error: &str) {
    let obj = json!({
        "event": "error",
        "timestamp": timestamp(),
        "sequence": sequence,
        "error": error,
    });
    println!("{}", serde_json::to_string(&obj).unwrap_or_default());
}

/// Emit a shutdown event.
pub fn emit_shutdown(sequence: u64) {
    let obj = json!({
        "event": "shutdown",
        "timestamp": timestamp(),
        "sequence": sequence,
    });
    println!("{}", serde_json::to_string(&obj).unwrap_or_default());
}

/// Current UTC timestamp in ISO 8601 format.
fn timestamp() -> String {
    Utc::now().to_rfc3339()
}
