use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Output, Stdio};
use std::sync::atomic::{AtomicU64, Ordering};

const EXIT_USAGE: i32 = 2;
const EXIT_INPUT: i32 = 3;
const EXIT_SERVICE: i32 = 4;

static TEMP_ID: AtomicU64 = AtomicU64::new(0);

struct TestDir(PathBuf);

impl TestDir {
    fn new(name: &str) -> Self {
        let id = TEMP_ID.fetch_add(1, Ordering::Relaxed);
        let path = std::env::temp_dir().join(format!(
            "metacrate-vivox-test-{name}-{}-{id}",
            std::process::id()
        ));
        fs::create_dir(&path).expect("create test directory");
        Self(path)
    }

    fn write(&self, contents: &str) -> PathBuf {
        let path = self.0.join("vivox.tsv");
        fs::write(&path, contents).expect("write fake Vivox script");
        path
    }
}

impl Drop for TestDir {
    fn drop(&mut self) {
        let _ = fs::remove_dir_all(&self.0);
    }
}

fn path_text(path: &Path) -> &str {
    path.to_str().expect("UTF-8 path")
}

fn run(args: &[&str]) -> Output {
    Command::new(env!("CARGO_BIN_EXE_vivox-test"))
        .args(args)
        .env_remove("GRID_FIRST_NAME")
        .env_remove("GRID_LAST_NAME")
        .env_remove("GRID_PASSWORD")
        .env_remove("GRID_LOGIN_URL")
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .output()
        .expect("run vivox-test")
}

fn utf8(bytes: &[u8]) -> &str {
    std::str::from_utf8(bytes).expect("UTF-8 process output")
}

fn assert_exit(output: &Output, expected: i32) {
    assert_eq!(
        output.status.code(),
        Some(expected),
        "stdout:\n{}\nstderr:\n{}",
        utf8(&output.stdout),
        utf8(&output.stderr)
    );
}

fn complete_script(extra: &str) -> String {
    format!(
        "capture-device\tFake Microphone\n\
         capture-device\tBackup Microphone\n\
         current-capture\tFake Microphone\n\
         render-device\tFake Speakers\n\
         current-render\tFake Speakers\n\
         provision\tvoice-user-secret\tfake-password-secret\tvoice.example.test\n\
         parcel\tScripted Region\t42\tsip:channel-token-secret@example.test\n\
         participant\tparticipant-secret\tAlice Resident\tsip:participant-token-secret@example.test\n\
         {extra}"
    )
}

#[test]
fn help_documents_prerequisites_gates_and_scripted_controls() {
    let output = run(&["--help"]);
    assert!(output.status.success());
    let help = utf8(&output.stdout);
    for marker in [
        "[FIRSTNAME]",
        "[LASTNAME]",
        "[PASSWORD]",
        "--fake-script",
        "--daemon-endpoint",
        "--allow-live-login",
        "--confirm-live-login",
        "--allow-session-audio",
        "proprietary Vivox SDK control service",
        "does not bundle, locate, start, or invoke",
        "capture-device",
        "participant",
    ] {
        assert!(help.contains(marker), "help omitted {marker}:\n{help}");
    }
    let output = run(&[]);
    assert_exit(&output, EXIT_USAGE);
}

#[test]
fn fake_tcp_service_exercises_full_flow_and_tears_down_without_secret_leaks() {
    let directory = TestDir::new("complete");
    let script = directory.write(&complete_script(""));
    let output = run(&[
        "--fake-script",
        path_text(&script),
        "--timeout-seconds",
        "5",
    ]);
    assert!(output.status.success(), "{}", utf8(&output.stderr));
    assert!(output.stderr.is_empty(), "{}", utf8(&output.stderr));
    let stdout = utf8(&output.stdout);
    for expected in [
        "* Fake Microphone",
        "  Backup Microphone",
        "* Fake Speakers",
        "Voice connector created: <redacted>",
        "Provisioned voice account logged in: <redacted>",
        "region=Scripted Region local-id=42 channel=<redacted-uri>",
        "Voice session connected: <redacted>",
        "Participant control validated for Alice Resident (URI redacted).",
        "Voice session terminated.",
        "Voice account logged out.",
        "requests=10 active-pipes=0 active-sessions=0 active-tasks=0",
    ] {
        assert!(stdout.contains(expected), "missing {expected}:\n{stdout}");
    }
    for secret in [
        "voice-user-secret",
        "fake-password-secret",
        "channel-token-secret",
        "participant-secret",
        "connector-secret",
        "account-secret",
        "session-secret",
    ] {
        assert!(
            !stdout.contains(secret),
            "stdout leaked {secret}:\n{stdout}"
        );
        assert!(
            !utf8(&output.stderr).contains(secret),
            "stderr leaked {secret}:\n{}",
            utf8(&output.stderr)
        );
    }
}

#[test]
fn rejection_is_reported_by_codes_redacts_echoed_password_and_still_shuts_down() {
    let directory = TestDir::new("rejection");
    let script = directory.write(&complete_script(
        "reject\tAccount.Login.1\t1\t403\tdenied fake-password-secret\n",
    ));
    let output = run(&["--fake-script", path_text(&script)]);
    assert_exit(&output, EXIT_SERVICE);
    let stderr = utf8(&output.stderr);
    assert!(stderr.contains("Account.Login.1"), "{stderr}");
    assert!(stderr.contains("return 1, status 403"), "{stderr}");
    assert!(stderr.contains("denied <redacted>"), "{stderr}");
    assert!(!stderr.contains("fake-password-secret"), "{stderr}");
}

#[test]
fn malformed_scripts_and_ungated_live_inputs_fail_before_network_access() {
    let directory = TestDir::new("invalid");
    let missing = directory.write("capture-device\tMicrophone\n");
    let output = run(&["--fake-script", path_text(&missing)]);
    assert_exit(&output, EXIT_INPUT);
    assert!(utf8(&output.stderr).contains("provision directive"));

    let output = run(&["First", "Last", "do-not-echo"]);
    assert_exit(&output, EXIT_USAGE);
    assert!(utf8(&output.stderr).contains("--allow-live-login"));
    assert!(!utf8(&output.stderr).contains("do-not-echo"));

    let output = run(&[
        "First",
        "Last",
        "do-not-echo",
        "--allow-live-login",
        "--confirm-live-login",
        "WRONG",
    ]);
    assert_exit(&output, EXIT_USAGE);
    assert!(!utf8(&output.stderr).contains("do-not-echo"));

    let valid = directory.write(&complete_script(""));
    let output = run(&[
        "First",
        "Last",
        "do-not-echo",
        "--fake-script",
        path_text(&valid),
    ]);
    assert_exit(&output, EXIT_USAGE);
    assert!(!utf8(&output.stderr).contains("do-not-echo"));
}
