//! Handler for `mcptest posture` (WOR-1432).
//!
//! Load or synthesize a deployment manifest, run the pure assessor, render the
//! report, and gate on `--threshold`. The report JSON folds straight into an
//! evidence pack via `mcptest evidence pack --posture`.

use anyhow::{Context, Result};

use mcptest_core::posture::{assess, DeploymentManifest, PostureReport};

use crate::cli::args::{PostureArgs, PostureFormat};
use crate::cli::exit_codes::{EXIT_COVERAGE_FLOOR, EXIT_INVALID_INVOCATION, EXIT_OK};

/// Assess runtime posture and print the report.
pub(crate) fn posture_command(args: &PostureArgs) -> Result<i32> {
    let (manifest, target) = match (&args.manifest, &args.stdio_command) {
        (Some(path), _) => {
            let text = std::fs::read_to_string(path)
                .with_context(|| format!("reading manifest {}", path.display()))?;
            let manifest = DeploymentManifest::parse(&text)
                .with_context(|| format!("parsing manifest {}", path.display()))?;
            (manifest, path.display().to_string())
        }
        (None, Some(cmd)) => (DeploymentManifest::for_stdio_command(cmd), cmd.clone()),
        (None, None) => {
            eprintln!("mcptest posture: pass --manifest <FILE> or --stdio-command <CMD>");
            return Ok(EXIT_INVALID_INVOCATION);
        }
    };

    let report = assess(&manifest, &target);
    match args.format {
        PostureFormat::Json => println!("{}", serde_json::to_string_pretty(&report)?),
        PostureFormat::Pretty => print_pretty(&report),
    }

    if let Some(threshold) = args.threshold {
        if report.score_pct() < threshold {
            eprintln!(
                "runtime posture {:.0}% is below the {threshold:.0}% threshold",
                report.score_pct()
            );
            return Ok(EXIT_COVERAGE_FLOOR);
        }
    }
    Ok(EXIT_OK)
}

/// Render the report as a human-friendly table.
fn print_pretty(report: &PostureReport) {
    println!(
        "Runtime posture for {} ({})",
        report.target, report.deployment_kind
    );
    println!();
    for check in &report.checks {
        println!(
            "  {:<5} {:<20} [{}] {}",
            check.status.glyph(),
            check.dimension.label(),
            evidence_label(check),
            check.detail,
        );
        if let Some(remediation) = &check.remediation {
            println!("        fix: {remediation}");
        }
    }
    println!();
    println!(
        "  {} pass, {} warn, {} fail, {} unknown ({:.0}% of scored checks pass)",
        report.passed,
        report.warned,
        report.failed,
        report.unknown,
        report.score_pct(),
    );
}

/// The lowercase evidence tag for the table.
fn evidence_label(check: &mcptest_core::posture::PostureCheck) -> &'static str {
    use mcptest_core::posture::Evidence;
    match check.evidence {
        Evidence::Observed => "observed",
        Evidence::Claimed => "claimed",
        Evidence::Unknown => "unknown",
    }
}
