use sal_process::{run, run_command, run_silent, RunError};
use std::env;

#[test]
fn test_run_simple_command() {
    let result = run_command("echo hello").unwrap();
    assert!(result.success);
    assert_eq!(result.code, 0);
    assert!(result.stdout.contains("hello"));
    assert!(result.stderr.is_empty());
}

#[test]
fn test_run_command_with_args() {
    let result = run_command("echo hello world").unwrap();
    assert!(result.success);
    assert_eq!(result.code, 0);
    assert!(result.stdout.contains("hello world"));
}

#[test]
fn test_run_silent() {
    let result = run_silent("echo silent test").unwrap();
    assert!(result.success);
    assert_eq!(result.code, 0);
    assert!(result.stdout.contains("silent test"));
}

#[test]
fn test_run_builder_pattern() {
    let result = run("echo builder test").silent(true).execute().unwrap();

    assert!(result.success);
    assert_eq!(result.code, 0);
    assert!(result.stdout.contains("builder test"));
}

#[test]
fn test_run_builder_die_false() {
    let result = run("false") // Command that always fails
        .die(false)
        .silent(true)
        .execute()
        .unwrap();

    assert!(!result.success);
    assert_ne!(result.code, 0);
}

#[test]
fn test_run_builder_die_true() {
    // Use a command that will definitely fail
    let result = run("exit 1") // Script that always fails
        .die(true)
        .silent(true)
        .execute();

    assert!(result.is_err());
}

#[test]
fn test_run_multiline_script() {
    let script = r#"
        echo "Line 1"
        echo "Line 2"
        echo "Line 3"
    "#;

    let result = run_command(script).unwrap();
    assert!(result.success);
    assert_eq!(result.code, 0);
    assert!(result.stdout.contains("Line 1"));
    assert!(result.stdout.contains("Line 2"));
    assert!(result.stdout.contains("Line 3"));
}

#[test]
fn test_run_script_with_shebang() {
    let script = r#"#!/bin/bash
        echo "Script with shebang"
        exit 0
    "#;

    let result = run_command(script).unwrap();
    assert!(result.success);
    assert_eq!(result.code, 0);
    assert!(result.stdout.contains("Script with shebang"));
}

#[test]
fn test_run_script_error_handling() {
    let script = r#"
        echo "Before error"
        false
        echo "After error"
    "#;

    let result = run(script).silent(true).execute();
    assert!(result.is_err());
}

#[test]
fn test_run_empty_command() {
    let result = run_command("");
    assert!(result.is_err());
    match result.unwrap_err() {
        RunError::EmptyCommand => {}
        _ => panic!("Expected EmptyCommand error"),
    }
}

#[test]
fn test_run_nonexistent_command() {
    let result = run("nonexistent_command_12345").silent(true).execute();
    assert!(result.is_err());
}

#[test]
fn test_run_with_environment_variables() {
    env::set_var("TEST_VAR", "test_value");

    #[cfg(target_os = "windows")]
    let script = "echo %TEST_VAR%";

    #[cfg(not(target_os = "windows"))]
    let script = r#"
        export TEST_VAR="test_value"
        echo $TEST_VAR
    "#;

    let result = run_command(script).unwrap();
    assert!(result.success);
    assert!(result.stdout.contains("test_value"));

    env::remove_var("TEST_VAR");
}

#[test]
fn test_run_with_working_directory() {
    // Test that commands run in the current working directory
    #[cfg(target_os = "windows")]
    let result = run_command("cd").unwrap();

    #[cfg(not(target_os = "windows"))]
    let result = run_command("pwd").unwrap();

    assert!(result.success);
    assert!(!result.stdout.is_empty());
}

#[test]
fn test_command_result_properties() {
    let result = run_command("echo test").unwrap();

    // Test all CommandResult properties
    assert!(!result.stdout.is_empty());
    assert!(result.stderr.is_empty());
    assert!(result.success);
    assert_eq!(result.code, 0);
}

#[test]
fn test_run_builder_log_option() {
    // Test that log option doesn't cause errors
    let result = run("echo log test")
        .log(true)
        .silent(true)
        .execute()
        .unwrap();

    assert!(result.success);
    assert!(result.stdout.contains("log test"));
}

#[test]
fn test_run_cross_platform_commands() {
    // Test commands that work on all platforms

    // Test echo command
    let result = run_command("echo cross-platform").unwrap();
    assert!(result.success);
    assert!(result.stdout.contains("cross-platform"));

    // Test basic shell operations
    #[cfg(target_os = "windows")]
    let result = run_command("dir").unwrap();

    #[cfg(not(target_os = "windows"))]
    let result = run_command("ls").unwrap();

    assert!(result.success);
}

#[test]
fn test_run_script_with_variables() {
    let script = r#"
        VAR="test_variable"
        echo "Variable value: $VAR"
    "#;

    let result = run_command(script).unwrap();
    assert!(result.success);
    assert!(result.stdout.contains("Variable value: test_variable"));
}

#[test]
fn test_run_script_with_conditionals() {
    #[cfg(target_os = "windows")]
    let script = r#"
        if "hello"=="hello" (
            echo Condition passed
        ) else (
            echo Condition failed
        )
    "#;

    #[cfg(not(target_os = "windows"))]
    let script = r#"
        if [ "hello" = "hello" ]; then
            echo "Condition passed"
        else
            echo "Condition failed"
        fi
    "#;

    let result = run_command(script).unwrap();
    assert!(result.success);
    assert!(result.stdout.contains("Condition passed"));
}

#[test]
fn test_run_script_with_loops() {
    #[cfg(target_os = "windows")]
    let script = r#"
        for %%i in (1 2 3) do (
            echo Number: %%i
        )
    "#;

    #[cfg(not(target_os = "windows"))]
    let script = r#"
        for i in 1 2 3; do
            echo "Number: $i"
        done
    "#;

    let result = run_command(script).unwrap();
    assert!(result.success);
    assert!(result.stdout.contains("Number: 1"));
    assert!(result.stdout.contains("Number: 2"));
    assert!(result.stdout.contains("Number: 3"));
}

#[test]
fn test_run_with_stderr_output() {
    // Test that stderr field exists and can be accessed
    let result = run_command("echo test").unwrap();
    assert!(result.success);
    // Just verify that stderr field exists and is accessible
    let _stderr_len = result.stderr.len(); // This verifies stderr field exists
}

#[test]
fn test_run_builder_chaining() {
    let result = run("echo chaining test")
        .silent(true)
        .die(true)
        .log(false)
        .execute()
        .unwrap();

    assert!(result.success);
    assert!(result.stdout.contains("chaining test"));
}
