package shell

import (
	"os"
	"os/exec"
	"strings"
	"testing"
	"time"
)

// 执行正常的命令
func TestExecute_Success(t *testing.T) {
	res, err := Execute(ExecuteParams{
		Cmd:     `echo hello`,
		Timeout: 2,
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if res.ExitCode != 0 {
		t.Fatalf("expected exit code 0, got %d", res.ExitCode)
	}
	if strings.TrimSpace(res.Stdout) != "hello" {
		t.Fatalf("unexpected stdout: %q", res.Stdout)
	}
}

// 执行命令不存在
func TestExecute_CommandNotFound(t *testing.T) {
	_, err := Execute(ExecuteParams{
		Cmd:     `this_command_should_not_exist_123`,
		Timeout: 1,
	})
	if err == nil {
		t.Fatalf("expected error, got nil")
	}
}

// 命令非零退出码
func TestExecute_NonZeroExit(t *testing.T) {
	res, err := Execute(ExecuteParams{
		Cmd:     `sh -c "exit 42"`,
		Timeout: 2,
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if res.ExitCode != 42 {
		t.Fatalf("expected exit code 42, got %d", res.ExitCode)
	}
}

// 命令超时退出时
func TestExecute_Timeout_KillProcessGroup(t *testing.T) {
	start := time.Now()

	res, err := Execute(ExecuteParams{
		Cmd:     `sh -c "sleep 100 & wait"`,
		Timeout: 1,
	})

	elapsed := time.Since(start)
	if elapsed > 5*time.Second {
		t.Fatalf("Execute hung too long: %v", elapsed)
	}

	if res.ExitCode != 124 {
		t.Fatalf("expected exit code 124, got %d", res.ExitCode)
	}

	if err != nil && err != ErrExecutorLostControl {
		t.Fatalf("unexpected error: %v", err)
	}
}

// 命令输出超限时
func TestExecute_OutputLimit(t *testing.T) {
	res, err := Execute(ExecuteParams{
		Cmd:     `sh -c "yes | head -c 2097152"`, // 2MB
		Timeout: 2,
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if len(res.Stdout) > 1<<20 {
		t.Fatalf("stdout exceeded limit: %d", len(res.Stdout))
	}
}

// 测试无孤儿进程
func TestExecute_NoOrphanProcess(t *testing.T) {
	_, _ = Execute(ExecuteParams{
		Cmd:     `sh -c "sleep 100 & wait"`,
		Timeout: 1,
	})

	time.Sleep(300 * time.Millisecond)

	out, _ := exec.Command("pgrep", "-f", "sleep 100").Output()
	if len(out) > 0 {
		t.Fatalf("orphan sleep process detected: %s", out)
	}
}

// 执行正常的命令
func TestExecute_Ls(t *testing.T) {
	res, err := Execute(ExecuteParams{
		Cmd:     "ls -l",
		Timeout: 2,
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	if res.ExitCode != 0 {
		t.Fatalf("expected exit code 0, got %d", res.ExitCode)
	}

	if strings.TrimSpace(res.Stdout) == "" {
		t.Fatalf("ls stdout should not be empty")
	}
}

// 展开"环境变量"
func TestExecute_WithEnvExpansion(t *testing.T) {
	home := os.Getenv("HOME")
	if home == "" {
		t.Skip("HOME not set")
	}

	res, err := Execute(ExecuteParams{
		Cmd:     `echo $HOME`,
		Timeout: 2,
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	if res.ExitCode != 0 {
		t.Fatalf("expected exit code 0, got %d", res.ExitCode)
	}

	if strings.TrimSpace(res.Stdout) != home {
		t.Fatalf("unexpected stdout: %q", res.Stdout)
	}
}
