package cmd

import (
	"context"
	"errors"
	"fmt"
	"path"
	"strings"
	"sync"

	"github.com/tidbcloud/controlplane9/internal/byoc"
	"github.com/tidbcloud/controlplane9/internal/host"
)

type byocRemoteImageRunner struct {
	selected *host.Session

	toolMu    sync.Mutex
	toolPath  string
	authMu    sync.Mutex
	authReady bool
}

// Run keeps registry auth on the remote host's tmpfs and performs every
// manifest read/copy on that host. Customer SSO remains local; only the
// short-lived ECR password crosses SSH on stdin.
//
//nolint:gocritic // Runner receives an immutable command contract by value.
func (r *byocRemoteImageRunner) Run(ctx context.Context, command byoc.Command) ([]byte, error) {
	if command.Name != "crane" {
		return nil, fmt.Errorf("BYOC remote image runner refuses command %q", command.Name)
	}
	if command.Dir != "" {
		return nil, errors.New("BYOC remote image runner refuses local working-directory overrides")
	}
	toolPath, err := r.ensureTool(ctx)
	if err != nil {
		return nil, err
	}
	argv := make([]string, 0, len(command.Args)+3)
	if len(command.Env) > 0 {
		if len(command.Env) != 1 || !strings.HasPrefix(command.Env[0], "DOCKER_CONFIG=") {
			return nil, errors.New("BYOC remote image runner accepts only a DOCKER_CONFIG override")
		}
		if err := r.ensureAuthDirectory(ctx); err != nil {
			return nil, err
		}
		argv = append(argv, "env", "DOCKER_CONFIG="+r.authDirectory())
	}
	argv = append(argv, toolPath)
	argv = append(argv, command.Args...)
	return host.RunSSH(ctx, r.selected, command.Stdin, argv...)
}

func (r *byocRemoteImageRunner) Cleanup(ctx context.Context) error {
	if r == nil || r.selected == nil || r.selected.Remote == nil {
		return errors.New("BYOC remote image runner is missing remote host metadata")
	}
	r.authMu.Lock()
	defer r.authMu.Unlock()
	_, err := host.RunSSH(ctx, r.selected, nil, "rm", "-rf", r.authDirectory())
	if err == nil {
		r.authReady = false
	}
	return err
}

func (r *byocRemoteImageRunner) ensureTool(ctx context.Context) (string, error) {
	r.toolMu.Lock()
	defer r.toolMu.Unlock()
	if r.toolPath != "" {
		return r.toolPath, nil
	}
	if r == nil || r.selected == nil || r.selected.Remote == nil {
		return "", errors.New("BYOC remote image runner is missing remote host metadata")
	}
	if strings.TrimSpace(r.selected.Remote.RemoteStateDir) == "" {
		return "", errors.New("BYOC remote image runner requires a remote state directory")
	}
	toolDirectory := path.Join(r.selected.Remote.RemoteStateDir, "tools", "registry")
	toolPath := path.Join(toolDirectory, "crane")
	if output, err := host.RunSSH(ctx, r.selected, nil, toolPath, "version"); err == nil &&
		strings.TrimSpace(string(output)) == byoc.PinnedCraneVersion {
		r.toolPath = toolPath
		return r.toolPath, nil
	}
	if _, err := host.RunSSH(ctx, r.selected, nil, "mkdir", "-p", toolDirectory); err != nil {
		return "", fmt.Errorf("create remote BYOC image tool directory: %w", err)
	}
	if _, err := host.RunSSH(
		ctx,
		r.selected,
		nil,
		"env",
		"GOBIN="+toolDirectory,
		"go",
		"install",
		byoc.PinnedCraneModule,
	); err != nil {
		return "", fmt.Errorf("build pinned BYOC image tool on remote host: %w", err)
	}
	output, err := host.RunSSH(ctx, r.selected, nil, toolPath, "version")
	if err != nil {
		return "", fmt.Errorf("verify pinned BYOC image tool on remote host: %w", err)
	}
	if version := strings.TrimSpace(string(output)); version != byoc.PinnedCraneVersion {
		return "", fmt.Errorf("remote BYOC image tool version %s, want %s", version, byoc.PinnedCraneVersion)
	}
	r.toolPath = toolPath
	return r.toolPath, nil
}

func (r *byocRemoteImageRunner) ensureAuthDirectory(ctx context.Context) error {
	r.authMu.Lock()
	defer r.authMu.Unlock()
	if r.authReady {
		return nil
	}
	if _, err := host.RunSSH(ctx, r.selected, nil, "rm", "-rf", r.authDirectory()); err != nil {
		return fmt.Errorf("reset remote temporary BYOC registry credentials: %w", err)
	}
	if _, err := host.RunSSH(ctx, r.selected, nil, "install", "-d", "-m", "0700", r.authDirectory()); err != nil {
		return fmt.Errorf("prepare remote temporary BYOC registry credentials: %w", err)
	}
	r.authReady = true
	return nil
}

func (r *byocRemoteImageRunner) authDirectory() string {
	instanceID := "unknown"
	if r != nil && r.selected != nil && r.selected.Remote != nil && strings.TrimSpace(r.selected.Remote.InstanceID) != "" {
		instanceID = r.selected.Remote.InstanceID
	}
	return path.Join("/dev/shm", "cp9-byoc-registry-"+instanceID)
}
