#[path = "support/utils.rs"]
mod _utils;

use _utils::{boxed_error, cleanup_run, create_client, new_run_id, print_summary, require};
use mubit_sdk::TransportMode;
use serde_json::{json, Value};
use std::error::Error;
use std::time::Instant;

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn Error>> {
    let name = "control_state_structured_variables";
    let started = Instant::now();
    let client = create_client().await?;
    let run_id = new_run_id("control_state_structured_variables");
    client.set_run_id(Some(run_id.clone()));
    client.set_transport(TransportMode::Http);

    let mut passed = true;
    let mut detail = "validated control structured variable state-management".to_string();
    let mut metrics = json!({});

    let scenario = async {
        let variable_name = "planner_state";
        let value_json = json!({ "phase": "draft", "confidence": 0.91_f32 }).to_string();

        let set = client
            .control
            .set_variable(json!({
                "run_id": run_id,
                "name": variable_name,
                "value_json": value_json,
                "source": "explicit",
            }))
            .await?;
        require(
            set.get("success").and_then(Value::as_bool).unwrap_or(false),
            format!("set_variable failed: {set}"),
        )?;

        let get = client
            .control
            .get_variable(json!({ "run_id": run_id, "name": variable_name }))
            .await?;
        let list = client
            .control
            .list_variables(json!({ "run_id": run_id }))
            .await?;
        let delete = client
            .control
            .delete_variable(json!({ "run_id": run_id, "name": variable_name }))
            .await?;

        require(get.is_object(), format!("get_variable failed: {get}"))?;
        require(list.is_object(), format!("list_variables failed: {list}"))?;
        require(
            delete
                .get("success")
                .and_then(Value::as_bool)
                .unwrap_or(false),
            format!("delete_variable failed: {delete}"),
        )?;

        let variables = list
            .get("variables")
            .and_then(Value::as_array)
            .ok_or_else(|| boxed_error(format!("list_variables payload invalid: {list}")))?;
        require(
            variables
                .iter()
                .any(|entry| entry.get("name").and_then(Value::as_str) == Some(variable_name)),
            format!("variable not present in list_variables: {list}"),
        )?;

        metrics = json!({
            "run_id": run_id,
            "variable_name": variable_name,
            "variable_count": variables.len(),
        });
        Ok::<(), Box<dyn Error>>(())
    }
    .await;

    if let Err(err) = scenario {
        passed = false;
        detail = err.to_string();
    }

    let cleanup_ok = cleanup_run(&client, &run_id).await;
    if !cleanup_ok {
        passed = false;
        detail = format!("{detail} | cleanup failures");
    }

    print_summary(
        name,
        passed,
        &detail,
        &metrics,
        started.elapsed().as_secs_f64(),
        cleanup_ok,
    );

    if passed {
        Ok(())
    } else {
        Err(boxed_error(detail))
    }
}
