//! Integration: spawn kebab and verify --json mode emits error.v1 ndjson
//! on stderr while non-json mode emits the legacy `error:` text prefix.
//!
//! The `config_invalid` code is triggered by supplying an *existing* but
//! malformed TOML file via `--config`. A file that exists but fails TOML
//! parsing is the reliable path to `config_invalid`. Supplying a path that
//! does not exist emits `config_not_found` instead (Bug #10 fix, v0.20.0
//! bugfix3); see `cli_config_not_found.rs` for those tests.

use std::process::Command;

fn kebab_bin() -> std::path::PathBuf {
    let manifest = env!("CARGO_MANIFEST_DIR");
    std::path::PathBuf::from(manifest)
        .parent()
        .unwrap()
        .parent()
        .unwrap()
        .join("target/debug/kebab")
}

fn xdg_envs(tmp: &std::path::Path) -> [(&'static str, std::path::PathBuf); 4] {
    [
        ("XDG_CONFIG_HOME", tmp.join("cfg")),
        ("XDG_DATA_HOME", tmp.join("data")),
        ("XDG_CACHE_HOME", tmp.join("cache")),
        ("XDG_STATE_HOME", tmp.join("state")),
    ]
}

#[test]
fn json_mode_emits_error_v1_on_config_invalid() {
    let tmp = tempfile::tempdir().unwrap();
    // Write a file that exists but is not valid TOML.
    let bad_config = tmp.path().join("bad.toml");
    std::fs::write(&bad_config, b"this is not { valid toml !!!").unwrap();

    let mut cmd = Command::new(kebab_bin());
    cmd.args(["--json", "--config", bad_config.to_str().unwrap(), "ingest"]);
    for (k, v) in xdg_envs(tmp.path()) {
        cmd.env(k, v);
    }

    let out = cmd.output().unwrap();
    assert!(
        !out.status.success(),
        "expected non-zero exit for config_invalid"
    );
    let exit_code = out.status.code().unwrap_or(-1);
    assert_eq!(exit_code, 2, "expected exit code 2, got {exit_code}");

    let stderr = String::from_utf8(out.stderr).unwrap();
    let first_line = stderr
        .lines()
        .next()
        .expect("stderr must have at least one line");
    let v: serde_json::Value =
        serde_json::from_str(first_line).expect("stderr first line must be valid JSON");

    assert_eq!(
        v.get("schema_version").and_then(|s| s.as_str()),
        Some("error.v1"),
        "schema_version must be error.v1"
    );
    assert_eq!(
        v.get("code").and_then(|s| s.as_str()),
        Some("config_invalid"),
        "code must be config_invalid"
    );
}

#[test]
fn text_mode_emits_legacy_error_format() {
    let tmp = tempfile::tempdir().unwrap();
    // Same trigger: an existing file with malformed TOML.
    let bad_config = tmp.path().join("bad.toml");
    std::fs::write(&bad_config, b"this is not { valid toml !!!").unwrap();

    let mut cmd = Command::new(kebab_bin());
    cmd.args(["--config", bad_config.to_str().unwrap(), "ingest"]);
    for (k, v) in xdg_envs(tmp.path()) {
        cmd.env(k, v);
    }

    let out = cmd.output().unwrap();
    assert!(
        !out.status.success(),
        "expected non-zero exit for config_invalid"
    );
    let exit_code = out.status.code().unwrap_or(-1);
    assert_eq!(exit_code, 2, "expected exit code 2, got {exit_code}");

    let stderr = String::from_utf8(out.stderr).unwrap();
    assert!(
        stderr.starts_with("error:"),
        "text mode stderr must start with 'error:', got: {stderr:?}"
    );
    assert!(
        !stderr.trim_start().starts_with('{'),
        "text mode stderr must NOT be JSON, got: {stderr:?}"
    );
}
