//! v5.1 c6 — multi-sim 并发 selftest example。
//!
//! 用法:
//!
//! ```bash
//! # 前置:每个 UDID 都用 smix capsule up 起 runner(不同 port)
//! smix capsule up <UDID1> --runner-port 22087
//! smix capsule up <UDID2> --runner-port 22088
//! # ... N 个
//!
//! cargo run --release --example selftest_multi -- \
//!     <UDID1>:22087 <UDID2>:22088 [<UDID3>:22089 ...]
//! ```
//!
//! 结果:`.smix/selftest-multi/<RFC3339>/<UDID>/result.json` × N + 顶层
//! `.smix/selftest-multi/<RFC3339>/summary.json`。退出码:0 = 所有 sim PASS;
//! 1 = 任一 sim fail(`worst_status == some_fail`);非 0 退出码 ≠ 1 = 调用
//! 本身错(usage / IO / 等)。
//!
//! CLI subcommand `smix selftest multi` + gate-multi.sh 留 c7。

use std::path::PathBuf;
use std::process::ExitCode;

use chrono::{SecondsFormat, Utc};

use smix_sdk::selftest::multi::{MultiSimStatus, MultiSimTarget, run_multi_selftest};

fn parse_target(arg: &str) -> Result<MultiSimTarget, String> {
    let (udid, port) = arg
        .split_once(':')
        .ok_or_else(|| format!("expected `<UDID>:<PORT>`, got `{arg}`"))?;
    let port: u16 = port
        .parse()
        .map_err(|e| format!("port `{port}` not u16: {e}"))?;
    if udid.is_empty() {
        return Err(format!("UDID empty in `{arg}`"));
    }
    Ok(MultiSimTarget {
        udid: udid.to_string(),
        runner_port: port,
    })
}

#[tokio::main(flavor = "multi_thread", worker_threads = 8)]
async fn main() -> ExitCode {
    let args: Vec<String> = std::env::args().skip(1).collect();
    if args.is_empty() {
        eprintln!(
            "usage: selftest_multi <UDID1>:<PORT1> <UDID2>:<PORT2> [...]\n\
             (前置:每个 UDID 都用 `smix capsule up <UDID> --runner-port <PORT>` 起好)"
        );
        return ExitCode::from(64);
    }

    let mut targets = Vec::with_capacity(args.len());
    for a in &args {
        match parse_target(a) {
            Ok(t) => targets.push(t),
            Err(e) => {
                eprintln!("selftest_multi: arg parse error: {e}");
                return ExitCode::from(64);
            }
        }
    }

    let run_id = Utc::now()
        .to_rfc3339_opts(SecondsFormat::Secs, true)
        .replace(':', "-");
    let runs_root = PathBuf::from(format!(".smix/selftest-multi/{run_id}"));

    eprintln!(
        "selftest_multi: spawning {} parallel sim selftest jobs (runs_root={})",
        targets.len(),
        runs_root.display()
    );
    for t in &targets {
        eprintln!("  - {} @ port {}", t.udid, t.runner_port);
    }

    match run_multi_selftest(targets, runs_root.clone()).await {
        Ok(summary) => {
            eprintln!(
                "selftest_multi: summary — worst={:?}, pass={}, fail={}, runs={}",
                summary.worst_status,
                summary.pass_count,
                summary.fail_count,
                summary.runs.len()
            );
            for row in &summary.runs {
                eprintln!(
                    "  - {} → status={} coverage={:.1}% caps={} capsule_unattributed={}",
                    row.udid,
                    row.status,
                    row.coverage_pct,
                    row.capability_count,
                    row.capsule_unattributed
                );
            }
            eprintln!(
                "selftest_multi: summary.json → {}",
                runs_root.join("summary.json").display()
            );
            match summary.worst_status {
                MultiSimStatus::AllPass => ExitCode::from(0),
                MultiSimStatus::SomeFail => ExitCode::from(1),
            }
        }
        Err(e) => {
            eprintln!("selftest_multi: run failed: {e}");
            ExitCode::from(2)
        }
    }
}
