package runtimeconfig

import (
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
)

// runtimeGOOS and runtimeGOARCH are variables so package tests can exercise
// platform-specific launch behavior.
var (
	runtimeGOOS   = runtime.GOOS
	runtimeGOARCH = runtime.GOARCH
)

// darwinArm64Available tests whether the process is running under Rosetta on
// an arm64 Mac.
var darwinArm64Available = func() bool {
	if runtimeGOOS != "darwin" {
		return false
	}
	output, err := exec.Command("sysctl", "-n", "hw.optional.arm64").Output()
	if err != nil {
		return false
	}
	return strings.TrimSpace(string(output)) == "1"
}

// RuntimeCommand returns the command and args AgentTeam should use when executing a
// runtime binary. Codex needs an Apple Silicon wrapper when AgentTeam itself is an
// amd64 process running under Rosetta, otherwise npm shims may load x64
// optional dependencies even on an arm64 Mac.
func RuntimeCommand(t RuntimeType, binary string, args []string) (string, []string) {
	binary = EffectiveRuntimeBinary(t, binary)
	t = EffectiveRuntimeType(t)
	if t == TypeCodex {
		return CodexLaunchCommand(binary, args)
	}
	if t == TypeKimi && runtimeGOOS == "windows" {
		if launchBinary, ok := windowsBatchShimBinary(binary); ok {
			// npm installs Kimi as a batch shim. CreateProcess cannot execute it
			// directly; /d disables cmd AutoRun and ConfigureProbeCommand /
			// configureRuntimeCommand keep this wrapper windowless.
			return "cmd.exe", []string{"/d", "/s", "/c", windowsBatchShimCommandLine(launchBinary, args)}
		}
	}
	return binary, append([]string(nil), args...)
}

func windowsBatchShimBinary(binary string) (string, bool) {
	launchBinary := binary
	if resolved, err := exec.LookPath(binary); err == nil && strings.TrimSpace(resolved) != "" {
		launchBinary = resolved
	}
	extension := strings.ToLower(filepath.Ext(strings.TrimSpace(launchBinary)))
	return launchBinary, extension == ".cmd" || extension == ".bat"
}

func windowsBatchShimCommandLine(binary string, args []string) string {
	parts := make([]string, 0, len(args)+1)
	parts = append(parts, `"`+strings.ReplaceAll(binary, `"`, `""`)+`"`)
	for _, arg := range args {
		parts = append(parts, `"`+strings.ReplaceAll(arg, `"`, `""`)+`"`)
	}
	// Prefixing with call keeps the first cmd token unquoted while still
	// allowing the npm-shim path itself to contain spaces.
	return "call " + strings.Join(parts, " ")
}

// CodexLaunchCommand returns the command and args for launching a Codex binary,
// applying the Apple Silicon Rosetta wrapper when needed.
func CodexLaunchCommand(binary string, args []string) (string, []string) {
	if strings.TrimSpace(binary) == "" {
		binary = "codex"
	}
	if runtimeGOOS == "windows" {
		if launchBinary, ok := windowsBatchShimBinary(binary); ok {
			// npm installs Codex as a batch shim on Windows. Route through
			// cmd.exe call so shim paths under Program Files preserve spaces.
			return "cmd.exe", []string{"/d", "/s", "/c", windowsBatchShimCommandLine(launchBinary, args)}
		}
	}
	if runtimeGOOS == "darwin" && runtimeGOARCH == "amd64" && darwinArm64Available() {
		return "/usr/bin/arch", append([]string{"-arm64", binary}, args...)
	}
	return binary, append([]string(nil), args...)
}
