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

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

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

    let mut passed = true;
    let mut detail = "validated helper context + diagnose + memory health flow".to_string();
    let mut metrics = json!({});

    let scenario = async {
        let mut remember = RememberOptions::new(
            "Deploys fail when the migration checksum is stale after a force-push.",
        );
        remember.run_id = Some(run_id.clone());
        remember.agent_id = Some("observer".to_string());
        remember.intent = Some("lesson".to_string());
        remember.lesson_type = Some("failure".to_string());
        remember.lesson_scope = Some("session".to_string());
        remember.lesson_importance = Some("high".to_string());
        remember.metadata = Some(json!({ "source": "rust-helper-example" }));
        client.remember(remember).await?;

        let mut context_opts = GetContextOptions::default();
        context_opts.run_id = Some(run_id.clone());
        context_opts.query = Some("Why did the deploy fail?".to_string());
        context_opts.entry_types = vec!["lesson".to_string()];
        context_opts.mode = Some("summary".to_string());
        let context = client.get_context(context_opts).await?;

        let mut diagnose = DiagnoseOptions::new("deploy failed because migration checksum is stale");
        diagnose.run_id = Some(run_id.clone());
        diagnose.error_type = Some("deploy".to_string());
        diagnose.limit = 5;
        let diagnosis = client.diagnose(diagnose).await?;

        let mut health_opts = MemoryHealthOptions::default();
        health_opts.run_id = Some(run_id.clone());
        health_opts.limit = 100;
        let health = client.memory_health(health_opts).await?;

        let section_summaries = context
            .get("section_summaries")
            .and_then(|value| value.as_array())
            .ok_or_else(|| boxed_error(format!("section summaries missing: {context}")))?;
        require(
            diagnosis
                .get("total_failure_lessons")
                .and_then(|value| value.as_u64())
                .unwrap_or(0)
                >= 1,
            format!("diagnose should surface a failure lesson: {diagnosis}"),
        )?;
        require(
            health.get("entry_counts").and_then(|value| value.as_object()).is_some(),
            format!("memory health missing entry counts: {health}"),
        )?;

        metrics = json!({
            "run_id": run_id,
            "section_count": section_summaries.len(),
            "total_failure_lessons": diagnosis.get("total_failure_lessons").cloned().unwrap_or(serde_json::Value::Null),
            "entry_count_keys": health.get("entry_counts").and_then(|value| value.as_object()).map(|map| map.len()).unwrap_or(0),
        });

        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))
    }
}
