package runtimeconfig

import (
	"context"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"

	"github.com/stretchr/testify/require"
)

func TestRuntimeCommandWrapsCodexOnAppleSiliconWhenAgentTeamIsAmd64(t *testing.T) {
	oldGOOS := runtimeGOOS
	oldGOARCH := runtimeGOARCH
	oldDarwinArm64Available := darwinArm64Available
	t.Cleanup(func() {
		runtimeGOOS = oldGOOS
		runtimeGOARCH = oldGOARCH
		darwinArm64Available = oldDarwinArm64Available
	})

	runtimeGOOS = "darwin"
	runtimeGOARCH = "amd64"
	darwinArm64Available = func() bool { return true }

	command, args := RuntimeCommand(TypeCodex, "/usr/local/bin/codex", []string{"app-server", "--help"})

	require.Equal(t, "/usr/bin/arch", command)
	require.Equal(t, []string{"-arm64", "/usr/local/bin/codex", "app-server", "--help"}, args)
}

func TestRuntimeCommandDoesNotWrapNonCodexRuntime(t *testing.T) {
	oldGOOS := runtimeGOOS
	oldGOARCH := runtimeGOARCH
	oldDarwinArm64Available := darwinArm64Available
	t.Cleanup(func() {
		runtimeGOOS = oldGOOS
		runtimeGOARCH = oldGOARCH
		darwinArm64Available = oldDarwinArm64Available
	})

	runtimeGOOS = "darwin"
	runtimeGOARCH = "amd64"
	darwinArm64Available = func() bool { return true }

	command, args := RuntimeCommand(TypeClaudeCode, "/usr/local/bin/claude", []string{"--version"})

	require.Equal(t, "/usr/local/bin/claude", command)
	require.Equal(t, []string{"--version"}, args)
}

func TestRuntimeCommandDoesNotWrapCodexWhenAppleSiliconIsUnavailable(t *testing.T) {
	oldGOOS := runtimeGOOS
	oldGOARCH := runtimeGOARCH
	oldDarwinArm64Available := darwinArm64Available
	t.Cleanup(func() {
		runtimeGOOS = oldGOOS
		runtimeGOARCH = oldGOARCH
		darwinArm64Available = oldDarwinArm64Available
	})

	runtimeGOOS = "darwin"
	runtimeGOARCH = "amd64"
	darwinArm64Available = func() bool { return false }

	command, args := RuntimeCommand(TypeCodex, "/usr/local/bin/codex", []string{"--version"})

	require.Equal(t, "/usr/local/bin/codex", command)
	require.Equal(t, []string{"--version"}, args)
}

func TestRuntimeCommandWrapsCodexWindowsBatchShim(t *testing.T) {
	oldGOOS := runtimeGOOS
	t.Cleanup(func() { runtimeGOOS = oldGOOS })
	runtimeGOOS = "windows"

	command, args := RuntimeCommand(TypeCodex, `D:\Program Files\nodejs\codex.cmd`, []string{"app-server"})

	require.Equal(t, "cmd.exe", command)
	require.Equal(t, []string{
		"/d", "/s", "/c", `call "D:\Program Files\nodejs\codex.cmd" "app-server"`,
	}, args)
}

func TestRuntimeCommandLeavesCodexExecutableUnwrappedOnWindows(t *testing.T) {
	oldGOOS := runtimeGOOS
	t.Cleanup(func() { runtimeGOOS = oldGOOS })
	runtimeGOOS = "windows"

	command, args := RuntimeCommand(TypeCodex, `C:\Tools\codex.exe`, []string{"app-server"})

	require.Equal(t, `C:\Tools\codex.exe`, command)
	require.Equal(t, []string{"app-server"}, args)
}

func TestRuntimeCommandWrapsKimiWindowsBatchShim(t *testing.T) {
	oldGOOS := runtimeGOOS
	t.Cleanup(func() { runtimeGOOS = oldGOOS })
	runtimeGOOS = "windows"

	command, args := RuntimeCommand(TypeKimi, `C:\Users\demo\AppData\Roaming\npm\kimi.cmd`, []string{"acp"})

	require.Equal(t, "cmd.exe", command)
	require.Equal(t, []string{
		"/d", "/s", "/c", `call "C:\Users\demo\AppData\Roaming\npm\kimi.cmd" "acp"`,
	}, args)
}

func TestRuntimeCommandLeavesKimiExecutableUnwrapped(t *testing.T) {
	oldGOOS := runtimeGOOS
	t.Cleanup(func() { runtimeGOOS = oldGOOS })
	runtimeGOOS = "windows"

	command, args := RuntimeCommand(TypeKimi, `C:\Tools\kimi.exe`, []string{"acp"})

	require.Equal(t, `C:\Tools\kimi.exe`, command)
	require.Equal(t, []string{"acp"}, args)
}

func TestRuntimeCommandRunsKimiWindowsBatchShimWithStdio(t *testing.T) {
	if runtime.GOOS != "windows" {
		t.Skip("Windows batch-shim integration")
	}
	dir := filepath.Join(t.TempDir(), "Kimi Code")
	require.NoError(t, os.MkdirAll(dir, 0o755))
	shim := filepath.Join(dir, "kimi.cmd")
	require.NoError(t, os.WriteFile(shim, []byte("@echo off\r\nif not \"%~1\"==\"acp\" exit /b 7\r\nset /p frame=\r\necho %frame%\r\n"), 0o755))

	cmd := RuntimeCommandContext(context.Background(), TypeKimi, shim, []string{"acp"})
	ConfigureProbeCommand(cmd)
	cmd.Stdin = strings.NewReader("ACP_STDIO_OK\n")
	output, err := cmd.CombinedOutput()

	require.NoError(t, err, string(output))
	require.Equal(t, "ACP_STDIO_OK", strings.TrimSpace(string(output)))
}

func TestRuntimeCommandRunsCodexWindowsBatchShimWithStdio(t *testing.T) {
	if runtime.GOOS != "windows" {
		t.Skip("Windows batch-shim integration")
	}
	dir := filepath.Join(t.TempDir(), "Codex CLI")
	require.NoError(t, os.MkdirAll(dir, 0o755))
	shim := filepath.Join(dir, "codex.cmd")
	require.NoError(t, os.WriteFile(shim, []byte("@echo off\r\nif not \"%~1\"==\"app-server\" exit /b 7\r\nset /p frame=\r\necho %frame%\r\n"), 0o755))

	cmd := RuntimeCommandContext(context.Background(), TypeCodex, shim, []string{"app-server"})
	ConfigureProbeCommand(cmd)
	cmd.Stdin = strings.NewReader("CODEX_STDIO_OK\n")
	output, err := cmd.CombinedOutput()

	require.NoError(t, err, string(output))
	require.Equal(t, "CODEX_STDIO_OK", strings.TrimSpace(string(output)))
}
