package host

import (
	"bytes"
	"context"
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/tidbcloud/controlplane9/internal/config"
	"github.com/tidbcloud/controlplane9/internal/verbose"
)

// RunKubectl executes kubectl against the selected host, locally or via ssh.
func RunKubectl(ctx context.Context, selected *Session, stdin []byte, args ...string) ([]byte, error) {
	if selected == nil {
		return nil, fmt.Errorf("selected host is required")
	}
	switch selected.Mode {
	case "", config.HostModeLocalK3d, config.HostModeRemoteEKS:
		return runLocalKubectl(ctx, selected, stdin, args...)
	case config.HostModeRemoteEC2K3d, config.HostModeRemoteGCEK3d:
		if selected.Remote == nil {
			return nil, fmt.Errorf("remote selected host metadata is not available")
		}
		if strings.TrimSpace(selected.Remote.RemoteKubeconfigPath) == "" {
			return nil, fmt.Errorf("remote selected host is missing remote kubeconfig path")
		}
		remoteArgs := make([]string, 0, len(args)+5)
		remoteArgs = append(remoteArgs, "kubectl", "--kubeconfig", selected.Remote.RemoteKubeconfigPath)
		if selected.Context != "" {
			remoteArgs = append(remoteArgs, "--context", selected.Context)
		}
		remoteArgs = append(remoteArgs, args...)
		return RunSSH(ctx, selected, stdin, remoteArgs...)
	default:
		return nil, fmt.Errorf("unsupported host mode %q", selected.Mode)
	}
}

func runLocalKubectl(ctx context.Context, selected *Session, stdin []byte, args ...string) ([]byte, error) {
	//nolint:gosec // kubectl args are derived from validated session metadata and generated callers.
	cmd := exec.CommandContext(ctx, "kubectl", selected.KubectlArgs(args...)...)
	if len(stdin) > 0 {
		cmd.Stdin = bytes.NewReader(stdin)
	}
	cmd.Env = append(os.Environ(), selected.KubectlEnv()...)
	output, err := verbose.RunCommand(cmd)
	if err != nil {
		return nil, fmt.Errorf("kubectl %v: %w\n%s", args, err, string(output))
	}
	return output, nil
}
