#[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;
use tokio::time::{sleep, Duration};

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

    let mut passed = true;
    let mut detail = "validated control query agent-routed flow".to_string();
    let mut metrics = json!({});

    let scenario = async {
        let accepted = client
            .control
            .ingest(json!({
                "run_id": run_id,
                "agent_id": "rust-sdk-example",
                "idempotency_key": format!("query-routed-{}", run_id),
                "parallel": false,
                "items": [
                    {
                        "item_id": "safety-incident-1",
                        "content_type": "text",
                        "text": "Safety briefing: forklift zone B had two near-miss events this week; camera review confirmed blind-spot congestion during shift handoff.",
                        "payload_json": "",
                        "hints_json": "{\"priority\":\"high\",\"signal\":\"safety\"}",
                        "metadata_json": "{\"source\":\"warehouse-safety\",\"zone\":\"B\",\"period\":\"weekly\"}",
                    },
                    {
                        "item_id": "product-telemetry-2",
                        "content_type": "text",
                        "text": "Product telemetry: onboarding completion rose from 61% to 74% after removing optional steps, but payment-link retries increased by 9%.",
                        "payload_json": "",
                        "hints_json": "{\"priority\":\"medium\",\"signal\":\"product-metrics\"}",
                        "metadata_json": "{\"source\":\"product-analytics\",\"funnel\":\"onboarding\",\"metric_window\":\"7d\"}",
                    },
                    {
                        "item_id": "support-escalation-3",
                        "content_type": "text",
                        "text": "Support escalation summary: three enterprise tickets cited delayed audit log exports; root cause traced to a throttling rule on shared workers.",
                        "payload_json": "",
                        "hints_json": "{\"priority\":\"high\",\"signal\":\"customer-impact\"}",
                        "metadata_json": "{\"source\":\"support-ops\",\"segment\":\"enterprise\",\"topic\":\"audit-logs\"}",
                    }
                ],
            }))
            .await?;

        let job_id = accepted
            .get("job_id")
            .or_else(|| accepted.get("jobId"))
            .and_then(Value::as_str)
            .ok_or_else(|| boxed_error(format!("ingest did not return job_id: {accepted}")))?
            .to_string();

        let mut done = false;
        for _ in 0..60 {
            let current = client
                .control
                .get_ingest_job(json!({ "run_id": run_id, "job_id": job_id }))
                .await?;
            if current
                .get("done")
                .and_then(Value::as_bool)
                .unwrap_or(false)
            {
                done = true;
                break;
            }
            sleep(Duration::from_millis(250)).await;
        }
        require(done, "ingest job did not complete before query")?;

        let response = client
            .control
            .query(json!({
                "run_id": run_id,
                "query": "summarize the safety, product, and support signals captured for this run",
                "schema": "",
                "mode": "agent_routed",
                "direct_lane": "semantic_search",
                "include_linked_runs": false,
                "limit": 5,
                "embedding": [],
            }))
            .await?;

        require(
            response.get("mode").and_then(Value::as_str) == Some("agent_routed"),
            format!("unexpected query mode: {response}"),
        )?;
        require(
            response
                .get("routing_summary")
                .and_then(Value::as_str)
                .map(|value| !value.trim().is_empty())
                .unwrap_or(false),
            format!("routing_summary should be non-empty: {response}"),
        )?;

        let consulted_runs = response
            .get("consulted_runs")
            .and_then(Value::as_array)
            .ok_or_else(|| boxed_error(format!("consulted_runs must be array: {response}")))?;
        require(
            consulted_runs
                .iter()
                .filter_map(Value::as_str)
                .any(|value| value == run_id || value.ends_with(&format!("::{run_id}"))),
            format!("consulted_runs missing primary run_id: {response}"),
        )?;

        require(
            response
                .get("final_answer")
                .and_then(Value::as_str)
                .map(|value| !value.trim().is_empty())
                .unwrap_or(false),
            format!("final_answer should be non-empty: {response}"),
        )?;

        let evidence_count = response
            .get("evidence")
            .and_then(Value::as_array)
            .map(std::vec::Vec::len)
            .unwrap_or(0);

        metrics = json!({
            "run_id": run_id,
            "job_id": job_id,
            "mode": response.get("mode").cloned().unwrap_or(Value::Null),
            "consulted_runs": consulted_runs,
            "evidence_count": evidence_count,
        });

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