//! Human-readable CLI diagnostics (2026-05-14): non-JSON `ail check` and
//! sibling subcommands surface `WorkspaceLoadError` with the same
//! bracketed `[code]` prefix that the JSON path emits.
//!
//! Before this iter, non-JSON CLI subcommands that called
//! `ailang_surface::load_workspace(&path)?` propagated the error
//! through `anyhow`'s Display, producing `Error: <message>` —
//! missing the bracketed diagnostic code that `--json` consumers
//! and humans alike use to triage. Fix: a `load_workspace_human`
//! helper routes through `workspace_error_to_diagnostic` and
//! prints `error: [<code>] <def>: <message>` before exiting.
//!
//! These tests pin the bracketed-code surface on a representative
//! workspace-load error (`module-not-found`). They are tempdir-
//! based: the fixture is authored at test time and removed at
//! drop, so no committed fixture is needed (the surface under
//! test is the CLI formatting, not a permanent corpus entry).

use std::io::Write;
use std::path::PathBuf;
use std::process::Command;

fn ail_bin() -> PathBuf {
    PathBuf::from(env!("CARGO_BIN_EXE_ail"))
}

/// Build a fresh tempdir containing one .ail module that imports a
/// non-existent sibling module. Returns the entry path. The tempdir
/// is leaked deliberately — tests are single-shot and tempdir
/// cleanup is the test harness's concern.
fn tempdir_with_missing_import() -> PathBuf {
    let dir = std::env::temp_dir().join(format!(
        "ail_cli_diag_human_{}",
        std::process::id()
    ));
    let _ = std::fs::remove_dir_all(&dir);
    std::fs::create_dir_all(&dir).expect("create tempdir");
    let entry = dir.join("test_missing_import.ail");
    let mut f = std::fs::File::create(&entry).expect("create entry .ail");
    writeln!(
        f,
        "(module test_missing_import\n  (import this_module_does_not_exist)\n  (fn main\n    (type (fn-type (params) (ret (own (con Unit))) (effects IO)))\n    (params)\n    (body (do io/print_str \"hello\"))))"
    ).expect("write fixture");
    entry
}

/// Property: `ail check <fixture>` (non-JSON path) on a workspace
/// with a missing import emits a stderr line of shape
/// `error: [module-not-found] ...` and exits non-zero. Pre-iter
/// behaviour was `Error: module ...` without the bracketed code;
/// this is the regression guard against re-introducing that.
#[test]
fn check_non_json_emits_bracketed_module_not_found() {
    let fixture = tempdir_with_missing_import();
    let output = Command::new(ail_bin())
        .args(["check", fixture.to_str().unwrap()])
        .output()
        .expect("ail binary must launch");
    assert!(
        !output.status.success(),
        "ail check must exit non-zero on missing import; stderr={}",
        String::from_utf8_lossy(&output.stderr),
    );
    let stderr = String::from_utf8_lossy(&output.stderr);
    assert!(
        stderr.contains("[module-not-found]"),
        "expected `[module-not-found]` in stderr, got: {stderr}"
    );
    assert!(
        stderr.starts_with("error: "),
        "expected stderr to start with `error: ` (lowercase, matching the JSON-mode wording), got: {stderr}"
    );
}
