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

    let mut passed = true;
    let mut detail = "validated raw upsert key idempotency".to_string();
    let mut metrics = json!({});

    let scenario = async {
        let idempotency_key = format!("idempotency-{run_id}");

        let first = client
            .control
            .ingest(json!({
                "run_id": run_id,
                "agent_id": "rust-sdk-example",
                "idempotency_key": idempotency_key,
                "parallel": false,
                "items": [
                    {
                        "item_id": "release-risk-1",
                        "content_type": "text",
                        "text": "Release planning memo: mobile v5.12 RC is blocked by an Android 15 beta crash loop triggered during background sync with low-memory pressure.",
                        "payload_json": "",
                        "hints_json": "{\"priority\":\"high\",\"signal\":\"release-risk\"}",
                        "metadata_json": "{\"source\":\"release-management\",\"platform\":\"android\",\"track\":\"v5.12\"}",
                    },
                    {
                        "item_id": "finance-recon-2",
                        "content_type": "text",
                        "text": "Finance operations note: invoice batch B-4402 contained three duplicate vendor IDs; reconciliation script flagged records for manual approval.",
                        "payload_json": "",
                        "hints_json": "{\"priority\":\"medium\",\"signal\":\"billing\"}",
                        "metadata_json": "{\"source\":\"finance-ops\",\"batch\":\"B-4402\",\"workflow\":\"reconciliation\"}",
                    }
                ],
            }))
            .await?;

        let second = client
            .control
            .ingest(json!({
                "run_id": run_id,
                "agent_id": "rust-sdk-example",
                "idempotency_key": idempotency_key,
                "parallel": false,
                "items": [{
                    "item_id": "procurement-followup-3",
                    "content_type": "text",
                    "text": "Procurement update: alternate supplier onboarding for lithium cells was escalated after lead-time slipped from 11 to 19 days in Q1 forecasts.",
                    "payload_json": "",
                    "hints_json": "{\"priority\":\"medium\",\"signal\":\"supply-chain\"}",
                    "metadata_json": "{\"source\":\"procurement\",\"component\":\"lithium-cell\",\"quarter\":\"Q1\"}",
                }],
            }))
            .await?;

        let first_job_id = first
            .get("job_id")
            .or_else(|| first.get("jobId"))
            .and_then(Value::as_str)
            .ok_or_else(|| boxed_error(format!("first ingest missing job_id: {first}")))?;
        let second_job_id = second
            .get("job_id")
            .or_else(|| second.get("jobId"))
            .and_then(Value::as_str)
            .ok_or_else(|| boxed_error(format!("second ingest missing job_id: {second}")))?;

        require(
            first_job_id == second_job_id,
            format!("idempotency should reuse job_id: {first} vs {second}"),
        )?;
        require(
            second
                .get("deduplicated")
                .and_then(Value::as_bool)
                .unwrap_or(false),
            format!("second ingest should be deduplicated: {second}"),
        )?;

        metrics = json!({
            "run_id": run_id,
            "job_id": first_job_id,
            "second_deduplicated": second.get("deduplicated").cloned().unwrap_or(Value::Bool(false)),
        });

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