//! Rust handler for the `greet_actor` operation. Copy this file to
//! `crates/ontoref-ops/src/ops/greet_actor.rs` and add
//! `pub mod greet_actor;` to `crates/ontoref-ops/src/ops/mod.rs`.
//!
//! The `#[onto_operation]` proc-macro emits a static `OperationEntry`
//! collected by `inventory::collect!(OperationEntry)` in
//! `crates/ontoref-ops/src/lib.rs`. No further registration is needed —
//! `cargo build -p ontoref-daemon` links the entry automatically.

use crate::context::OpContext;
use crate::error::OpError;
use crate::output::OpOutput;
use ontoref_derive::onto_operation;
use serde_json::json;

/// Returns a personalised greeting for the given actor id; records the
/// latest greeting in the actor-greeting FSM dimension.
#[onto_operation(
    id             = "greet_actor",
    validation_sla = "Synchronous",
)]
pub fn greet_actor(
    inputs: &serde_json::Value,
    ctx: &mut OpContext,
) -> Result<OpOutput, OpError> {
    let actor_id = inputs
        .get("actor_id")
        .and_then(|v| v.as_str())
        .ok_or(OpError::MissingInput { field: "actor_id" })?;

    let tone = inputs
        .get("tone")
        .and_then(|v| v.as_str())
        .ok_or(OpError::MissingInput { field: "tone" })?;

    let greeting = match tone {
        "formal" => format!("Good day, {actor_id}."),
        "casual" => format!("hey {actor_id}!"),
        "dao" => format!("namaste, {actor_id} — flow continues."),
        other => {
            return Err(OpError::ValidatorRejected {
                validator: "tone_in_allowed_set",
                reason: format!("tone '{other}' not in [formal|casual|dao]"),
            });
        }
    };

    ctx.record_state_transition(
        "actor-greeting",
        "current_state",
        json!({ "actor_id": actor_id, "greeting": &greeting }),
    )?;

    Ok(OpOutput::with_payload(json!({
        "actor_id": actor_id,
        "greeting": greeting,
        "tone":     tone,
    })))
}
