#[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_goal_tree_and_goal_update";
    let started = Instant::now();
    let client = create_client().await?;
    let run_id = new_run_id("internal_goal_tree");
    client.set_run_id(Some(run_id.clone()));
    client.set_transport(TransportMode::Http);
    let mut passed = true;
    let mut detail = "validated raw goal tree lifecycle".to_string();
    let mut metrics = json!({});

    let scenario = async {
        let parent = client.control.add_goal(json!({"run_id": run_id, "description": "Resolve claim", "priority": "high"})).await?;
        let parent_id = parent.get("id").and_then(Value::as_str).ok_or_else(|| boxed_error(format!("add_goal parent failed: {parent}")))?.to_string();
        let child = client.control.add_goal(json!({"run_id": run_id, "description": "Verify receipts", "priority": "medium", "parent_goal_id": parent_id})).await?;
        let child_id = child.get("id").and_then(Value::as_str).ok_or_else(|| boxed_error(format!("add_goal child failed: {child}")))?.to_string();
        let updated = client.control.update_goal(json!({"run_id": run_id, "goal_id": child_id, "status": "achieved"})).await?;
        let listed = client.control.list_goals(json!({"run_id": run_id})).await?;
        let tree = client.control.get_goal_tree(json!({"run_id": run_id, "root_goal_id": parent_id})).await?;
        require(updated.get("success").and_then(Value::as_bool).unwrap_or(true), format!("update_goal failed: {updated}"))?;
        require(listed.get("goals").and_then(|v| v.as_array()).map(|items| items.iter().any(|item| item.get("id").and_then(|v| v.as_str()) == Some(child_id.as_str()))).unwrap_or(false), format!("list_goals missing child: {listed}"))?;
        require(tree.get("goals").is_some() || tree.get("root").is_some() || tree.get("nodes").is_some(), format!("goal tree malformed: {tree}"))?;
        metrics = json!({"run_id": run_id, "parent_goal_id": parent_id, "child_goal_id": child_id});
        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)) }
}
