#[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 = "internal_legacy_state_compatibility";
    let started = Instant::now();
    let client = create_client().await?;
    let run_id = new_run_id("internal_legacy_state_compatibility");
    let linked_run_id = new_run_id("control_legacy_state_linked");
    client.set_run_id(Some(run_id.clone()));
    client.set_transport(TransportMode::Http);

    let mut passed = true;
    let mut detail = "validated legacy state compatibility APIs".to_string();
    let mut metrics = json!({});

    let scenario = async {
        let set_var = client.control.set_variable(json!({"run_id": run_id, "name": "claim_status", "value_json": json!({"value": "triage"}).to_string(), "source": "explicit"})).await?;
        let get_var = client.control.get_variable(json!({"run_id": run_id, "name": "claim_status"})).await?;
        let list_vars = client.control.list_variables(json!({"run_id": run_id})).await?;
        let delete_var = client.control.delete_variable(json!({"run_id": run_id, "name": "claim_status"})).await?;

        let define_concept = client.control.define_concept(json!({"run_id": run_id, "name": "claim", "schema_json": json!({"type": "object", "properties": {"status": {"type": "string"}}}).to_string()})).await?;
        let list_concepts = client.control.list_concepts(json!({"run_id": run_id})).await?;

        let add_goal = client.control.add_goal(json!({"run_id": run_id, "description": "Resolve claim", "priority": "high"})).await?;
        let goal_id = add_goal.get("id").and_then(Value::as_str).ok_or_else(|| boxed_error(format!("add_goal failed: {add_goal}")))?.to_string();
        let update_goal = client.control.update_goal(json!({"run_id": run_id, "goal_id": goal_id, "status": "suspended"})).await?;
        let list_goals = client.control.list_goals(json!({"run_id": run_id})).await?;
        let goal_tree = client.control.get_goal_tree(json!({"run_id": run_id, "root_goal_id": goal_id})).await?;

        let submit_action = client.control.submit_action(json!({"run_id": run_id, "agent_id": "planner", "action_type": "note", "action_json": json!({"step": "inspect facts"}).to_string()})).await?;
        let action_log = client.control.get_action_log(json!({"run_id": run_id, "limit": 10})).await?;
        let run_cycle = client.control.run_cycle(json!({"run_id": run_id, "agent_id": "planner", "candidates": [{"action_type": "inspect", "action_json": json!({"target": "claim facts"}).to_string(), "score": 0.9, "rationale": "highest confidence"}]})).await?;
        let cycle_history = client.control.get_cycle_history(json!({"run_id": run_id, "limit": 10})).await?;
        let link_run = client.control.link_run(json!({"run_id": run_id, "linked_run_id": linked_run_id})).await?;
        let unlink_run = client.control.unlink_run(json!({"run_id": run_id, "linked_run_id": linked_run_id})).await?;

        require(set_var.get("success").and_then(Value::as_bool).unwrap_or(false), format!("set_variable failed: {set_var}"))?;
        require(get_var.get("name").and_then(Value::as_str) == Some("claim_status"), format!("get_variable failed: {get_var}"))?;
        require(list_vars.get("variables").and_then(Value::as_array).map(|items| items.iter().any(|item| item.get("name").and_then(Value::as_str) == Some("claim_status"))).unwrap_or(false), format!("list_variables failed: {list_vars}"))?;
        require(delete_var.get("success").and_then(Value::as_bool).unwrap_or(false), format!("delete_variable failed: {delete_var}"))?;
        require(define_concept.get("success").and_then(Value::as_bool).unwrap_or(false), format!("define_concept failed: {define_concept}"))?;
        require(list_concepts.get("concepts").and_then(Value::as_array).map(|items| items.iter().any(|item| item.get("name").and_then(Value::as_str) == Some("claim"))).unwrap_or(false), format!("list_concepts failed: {list_concepts}"))?;
        require(update_goal.get("success").and_then(Value::as_bool).unwrap_or(false), format!("update_goal failed: {update_goal}"))?;
        require(list_goals.get("goals").and_then(Value::as_array).map(|items| items.iter().any(|item| item.get("id").and_then(Value::as_str) == Some(goal_id.as_str()))).unwrap_or(false), format!("list_goals failed: {list_goals}"))?;
        require(
            goal_tree.get("root").is_some()
                || goal_tree.get("nodes").is_some()
                || goal_tree.get("goals").and_then(Value::as_array).is_some(),
            format!("goal_tree failed: {goal_tree}"),
        )?;
        require(submit_action.get("success").and_then(Value::as_bool).unwrap_or(false), format!("submit_action failed: {submit_action}"))?;
        require(action_log.get("entries").and_then(Value::as_array).is_some(), format!("action_log failed: {action_log}"))?;
        let cycle_number_valid = run_cycle.get("cycle_number").and_then(Value::as_u64).is_some()
            || run_cycle
                .get("cycle_number")
                .and_then(Value::as_str)
                .map(|value| value.chars().all(|ch| ch.is_ascii_digit()))
                .unwrap_or(false);
        require(cycle_number_valid, format!("run_cycle failed: {run_cycle}"))?;
        require(cycle_history.get("cycles").and_then(Value::as_array).is_some(), format!("cycle_history failed: {cycle_history}"))?;
        require(link_run.get("success").and_then(Value::as_bool).unwrap_or(false), format!("link_run failed: {link_run}"))?;
        require(unlink_run.get("success").and_then(Value::as_bool).unwrap_or(false), format!("unlink_run failed: {unlink_run}"))?;

        metrics = json!({
            "run_id": run_id,
            "goal_id": goal_id,
            "action_id": submit_action.get("action_id").cloned().unwrap_or(Value::Null),
            "cycle_number": run_cycle.get("cycle_number").cloned().unwrap_or(Value::Null),
        });
        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)) }
}
