package doctor

import (
	"context"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"strings"
	"time"

	awssdk "github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/service/ec2"
	"github.com/aws/aws-sdk-go-v2/service/ssm"

	cpaws "github.com/tidbcloud/controlplane9/internal/aws"
	"github.com/tidbcloud/controlplane9/internal/config"
	"github.com/tidbcloud/controlplane9/internal/host"
	"github.com/tidbcloud/controlplane9/internal/host/remoteimage"
	cptilt "github.com/tidbcloud/controlplane9/internal/tilt"
	"github.com/tidbcloud/controlplane9/internal/verbose"
)

var doctorCommandTimeout = 10 * time.Second

var (
	doctorLoadAWSConfig                       = cpaws.LoadAWSConfig
	doctorLoadAWSConfigFromExportedCredential = cpaws.LoadAWSConfigFromExportedProfileCredentials
	doctorNewSTSClient                        = cpaws.NewSTSClient
	doctorNewRemoteImageEC2Client             = func(cfg awssdk.Config) remoteimage.EC2API { return ec2.NewFromConfig(cfg) }
	doctorNewRemoteImageSSMClient             = func(cfg awssdk.Config) remoteimage.SSMAPI { return ssm.NewFromConfig(cfg) }
	doctorValidateIAM                         = cpaws.ValidateIAMReadiness
	doctorValidateIAMCleanup                  = cpaws.ValidateIAMCleanupReadinessFromConfig
	doctorValidateUserManagedEC2Key           = cpaws.ValidateUserManagedEC2Key
	doctorResolveRemoteImagePlan              = resolveRemoteImagePlan
	doctorLookPath                            = exec.LookPath
	doctorRunCommand                          = verbose.RunCommand
	doctorRunSSH                              = host.RunSSH
)

// CheckDocker verifies the Docker daemon is running and accessible.
func CheckDocker(r *Result) {
	_, _ = checkRequiredLocalCommand(
		r,
		"docker",
		[]string{"info"},
		"Docker daemon is running",
		"Docker daemon is not running or not accessible",
		"install Docker Desktop, start Docker, or add docker to PATH",
	)
}

// CheckK3d verifies that the k3d binary is installed.
func CheckK3d(r *Result) {
	output, ok := checkRequiredLocalCommand(
		r,
		"k3d",
		[]string{"version"},
		"",
		"k3d binary is not working",
		"install k3d or add its install directory to PATH",
	)
	if !ok {
		return
	}
	version := strings.TrimSpace(strings.Split(string(output), "\n")[0])
	r.Pass("k3d", fmt.Sprintf("k3d installed (%s)", version))
}

// CheckKubectl verifies that kubectl is installed.
func CheckKubectl(r *Result) {
	_, _ = checkRequiredLocalCommand(
		r,
		"kubectl",
		[]string{"version", "--client", "--output=json"},
		"kubectl installed",
		"kubectl binary is not working",
		"install kubectl or add its install directory to PATH",
	)
}

// CheckTilt verifies that tilt is installed for local lifecycle control.
func CheckTilt(r *Result) {
	_, _ = checkRequiredLocalCommand(
		r,
		"tilt",
		[]string{"version"},
		"tilt installed",
		"tilt binary is not working",
		"install tilt or add its install directory to PATH",
	)
}

// CheckHelm verifies that Helm is installed for local Tilt resources.
func CheckHelm(r *Result) {
	_, _ = checkRequiredLocalCommand(
		r,
		"helm",
		[]string{"version", "--short"},
		"helm installed",
		"helm binary is not working",
		"install Helm or add its install directory to PATH (macOS: brew install helm)",
	)
}

// CheckRsync verifies the resumable remote-controller input sync dependency.
func CheckRsync(r *Result) {
	_, _ = checkRequiredLocalCommand(
		r,
		"rsync",
		[]string{"--version"},
		"rsync installed",
		"rsync binary is not working",
		"install rsync or add it to PATH (macOS: brew install rsync)",
	)
}

// CheckRemoteControllerTools verifies the controller binaries installed by
// remote host bootstrap. Remote sessions do not require local Tilt or Helm.
func CheckRemoteControllerTools(r *Result, selected *host.Session) {
	if selected == nil || selected.Remote == nil {
		r.Pass("remote-controller-tools", "Tilt and Helm will be installed during remote host bootstrap")
		return
	}
	ctx, cancel := context.WithTimeout(context.Background(), doctorTimeout(selected))
	defer cancel()
	output, err := doctorRunSSH(
		ctx,
		selected,
		nil,
		"sh",
		"-lc",
		"tilt version && helm version --short",
	)
	if err != nil {
		r.FailActionable(
			"remote-controller-tools",
			"remote Tilt or Helm is unavailable",
			fmt.Sprintf("reason: %v\noutput: %s", err, strings.TrimSpace(string(output))),
			"remote-controller-tools-missing",
			"host.ec2",
			"rerun `cp9 up config=cp9.yaml`; remote host bootstrap installs the pinned Tilt and Helm versions",
		)
		return
	}
	r.Pass("remote-controller-tools", "remote Tilt and Helm are available")
}

// CheckMySQL verifies that the mysql client needed by Premium SQL proof trains is installed.
func CheckMySQL(r *Result) {
	_, _ = checkRequiredLocalCommand(
		r,
		"mysql",
		[]string{"--version"},
		"mysql client installed",
		"mysql client is not working",
		"install MySQL client and add it to PATH (macOS: brew install mysql-client && export PATH=\"/opt/homebrew/opt/mysql-client/bin:$PATH\")",
	)
}

// CheckTerraform verifies that terraform is installed for substrate lifecycle control.
func CheckTerraform(r *Result) {
	_, _ = checkRequiredLocalCommand(
		r,
		"terraform",
		[]string{"version", "-json"},
		"terraform installed",
		"terraform binary is not working",
		"install terraform or add its install directory to PATH",
	)
}

// CheckAWSNuke verifies that aws-nuke is installed for scoped destroy cleanup.
func CheckAWSNuke(r *Result) {
	_, _ = checkRequiredLocalCommand(
		r,
		"aws-nuke",
		[]string{"--version"},
		"aws-nuke installed",
		"aws-nuke binary is not working",
		"install aws-nuke or add its install directory to PATH",
	)
}

// CheckProtoc verifies that protoc is installed.
func CheckProtoc(r *Result) {
	cmd := exec.Command("protoc", "--version")
	output, err := doctorRunCommand(cmd)
	if err != nil {
		r.Warn("protoc", "protoc not found (needed only if generating stubs from proto)", err.Error())
		return
	}
	version := strings.TrimSpace(string(output))
	r.Pass("protoc", fmt.Sprintf("protoc installed (%s)", version))
}

// CheckAWSCredentials verifies that AWS credentials are configured.
func CheckAWSCredentials(r *Result, profile string) {
	args := []string{"sts", "get-caller-identity"}
	if profile != "" {
		args = append(args, "--profile", profile)
	}
	cmd := exec.Command("aws", args...)
	if _, err := doctorRunCommand(cmd); err != nil {
		r.Warn("aws", "AWS credentials not valid or aws CLI not installed",
			fmt.Sprintf("profile=%q: %v", profile, err))
		return
	}
	r.Pass("aws", fmt.Sprintf("AWS credentials valid (profile=%q)", profile))
}

// RunPreflightChecks runs all pre-flight checks.
func RunPreflightChecks(
	r *Result,
	awsProfile string,
	selected *host.Session,
	session *config.SessionConfig,
	ownerAllowlist map[string][]string,
) {
	if selected != nil {
		r.Pass("host-mode", fmt.Sprintf("selected host mode: %s", selected.Mode))
	} else {
		r.Warn("host-mode", "selected host mode unavailable", "no host/session contract resolved")
	}

	switch {
	case selected == nil, selected.Mode == config.HostModeLocalK3d:
		CheckDocker(r)
		CheckK3d(r)
	case selected.Mode == config.HostModeRemoteEC2K3d:
		if selected.Remote == nil {
			r.Pass(
				"host-prereqs",
				"remote host metadata is not expected until the first cp9 up",
			)
		} else if err := runSSHWithTimeout(selected, "true"); err != nil {
			r.FailActionable(
				"remote-ssh",
				"remote EC2 host is not reachable over ssh",
				err.Error(),
				"remote-ssh-unreachable",
				"host.ec2",
				"verify the remote EC2 host is running, the SSH key is valid, and the security group allows SSH",
			)
		} else {
			r.Pass("remote-ssh", "remote EC2 host is reachable over ssh")
			if CheckRemoteDocker(r, selected) {
				CheckRemoteK3d(r, selected)
			}
		}
	default:
		r.Warn("host-prereqs", fmt.Sprintf("unknown host mode %q", selected.Mode), "")
	}

	CheckKubectl(r)
	if selected != nil && selected.Mode == config.HostModeRemoteEC2K3d {
		CheckRsync(r)
		CheckRemoteControllerTools(r, selected)
	} else {
		CheckTilt(r)
		CheckHelm(r)
	}
	// Stubs were part of the retired service graph, so nothing in a session can
	// declare a proto-backed stub any more.
	r.Pass("protoc", "protoc not required (the Session Tiltfile owns the service graph)")
	if sessionNeedsMySQL(session) {
		CheckMySQL(r)
	}
	if session != nil && session.APIVersion == config.APIVersionV1Alpha2 {
		if config.UsesCloudSubstrate(session) {
			CheckTerraform(r)
			CheckAWSNuke(r)
			CheckSessionIAM(r, session, selected, ownerAllowlist)
		} else {
			CheckLocalSessionIdentity(r, session)
		}
		CheckPremiumRemoteBuildContract(r, session, selected)
		r.Pass("network", "network/tunnel not required for this session")
		return
	}
	CheckAWSCredentials(r, awsProfile)
}

// CheckLocalSessionIdentity reports the same deterministic internal owner and
// Session tags that the local lifecycle persists, without requiring AWS.
func CheckLocalSessionIdentity(r *Result, session *config.SessionConfig) {
	if session == nil {
		r.Warn("session-identity", "local Session identity unavailable", "session config is nil")
		return
	}
	owner, tags, err := cpaws.ResolveLocalSessionIdentity(session.Name)
	if err != nil {
		r.Fail("session-identity", "local Session identity invalid", err.Error())
		return
	}
	r.Pass(
		"session-identity",
		fmt.Sprintf(
			"local Session identity ready (owner=%s cp9-owner=%s cp9-session=%s)",
			owner,
			tags[cpaws.TagOwner],
			tags[cpaws.TagSession],
		),
	)
}

func sessionNeedsMySQL(session *config.SessionConfig) bool {
	return session != nil &&
		session.APIVersion == config.APIVersionV1Alpha2 &&
		config.SessionPersona(session) == "dev-full"
}

func checkRequiredLocalCommand(
	r *Result,
	name string,
	args []string,
	passMessage string,
	executionFailureMessage string,
	fix string,
) ([]byte, bool) {
	binary, err := doctorLookPath(name)
	if err != nil {
		r.FailActionable(name, fmt.Sprintf("%s is not on PATH", name), fmt.Sprintf(
			"binary: %s\nreason: %v\nfix: %s",
			name,
			err,
			fix,
		), "missing-binary", "PATH", fix)
		return nil, false
	}
	ctx, cancel := context.WithTimeout(context.Background(), doctorCommandTimeout)
	defer cancel()
	cmd := exec.CommandContext(ctx, binary, args...)
	output, err := doctorRunCommand(cmd)
	if err != nil {
		reason := err
		if errors.Is(ctx.Err(), context.DeadlineExceeded) {
			reason = fmt.Errorf("command timed out after %s: %w", doctorCommandTimeout, ctx.Err())
		}
		r.FailActionable(name, executionFailureMessage, fmt.Sprintf(
			"binary: %s\npath: %s\nreason: %v\nfix: %s",
			name,
			binary,
			reason,
			fix,
		), "binary-execution-failed", name, fix)
		return output, false
	}
	if passMessage != "" {
		r.Pass(name, passMessage)
	}
	return output, true
}

// CheckSessionIAM verifies the local AWS/IAM contract for a v1alpha2 session.
func CheckSessionIAM(
	r *Result,
	session *config.SessionConfig,
	selected *host.Session,
	ownerAllowlist map[string][]string,
) {
	if session == nil {
		r.Warn("aws-iam", "session IAM contract unavailable", "session config is nil")
		return
	}
	ctx := context.Background()
	profile := sessionIAMPreflightProfile(session.Target.AWS.IAM)
	awsCfg, err := doctorLoadAWSConfig(ctx, profile, session.Target.Region)
	if err != nil {
		field := "target.aws.iam.source_profile"
		fix := "run `aws sso login --profile " + profile + "` or update target.aws.iam.source_profile"
		r.FailActionable("aws-iam", "local AWS/IAM contract invalid", actionableIAMBlocker(
			field,
			"AWS profile can load credentials for the target region",
			fix,
			err,
		), "source-profile-missing", field, fix)
		return
	}
	result, err := doctorValidateIAM(
		ctx,
		doctorNewSTSClient(&awsCfg),
		profile,
		session.Target.Region,
		session.Target.AWS.IAM.RoleARN,
		session.Name,
		ownerAllowlist,
	)
	if err != nil {
		if cpaws.IsSSOCredentialRefreshError(err) {
			exportedCfg, exportErr := doctorLoadAWSConfigFromExportedCredential(ctx, profile, session.Target.Region, nil)
			if exportErr == nil {
				awsCfg = exportedCfg
				result, err = doctorValidateIAM(
					ctx,
					doctorNewSTSClient(&awsCfg),
					profile,
					session.Target.Region,
					session.Target.AWS.IAM.RoleARN,
					session.Name,
					ownerAllowlist,
				)
				if err == nil {
					cpaws.PrefixCredentialSource(result, "aws-cli-export")
				}
			} else {
				err = fmt.Errorf("%w; AWS CLI credential export fallback failed: %w", err, exportErr)
			}
		}
		if err != nil {
			r.FailActionable("aws-iam", "local AWS/IAM contract invalid", actionableIAMBlocker(
				"target.aws.iam.role_arn",
				"caller can assume the cp9 developer role with owner/session tags",
				"run `cp9 setup` and update target.aws.iam.source_profile, target.aws.iam.role_arn, or ci.owner_allowlist from its output",
				err,
			), sessionIAMContractFailureClass(err), "target.aws.iam.role_arn", "run `cp9 setup` and update target.aws.iam.source_profile, target.aws.iam.role_arn, or ci.owner_allowlist from its output")
			return
		}
	}
	if err := doctorValidateIAMCleanup(ctx, &awsCfg, result, session.Name); err != nil {
		r.FailActionable("aws-iam", "local AWS/IAM cleanup contract invalid", actionableIAMBlocker(
			"target.aws.iam.role_arn",
			"role can validate cp9 cleanup permissions for this session",
			"run cp9 setup after applying the latest cp9 developer IAM policy",
			err,
		), "aws-iam-cleanup-contract-invalid", "target.aws.iam.role_arn", "run cp9 setup after applying the latest cp9 developer IAM policy")
		return
	}
	if session.Host.Mode == config.HostModeRemoteEC2K3d {
		persistedInstanceID := ""
		if selected != nil && selected.Remote != nil {
			persistedInstanceID = selected.Remote.InstanceID
		}
		effectiveAWSConfig := cpaws.EffectiveAWSConfig(&awsCfg, result)
		validation, err := doctorValidateUserManagedEC2Key(
			ctx,
			&effectiveAWSConfig,
			result.Account,
			session.Target.Region,
			session.Host.EC2.KeyPair,
			session.Host.EC2.SSHPrivateKey,
			persistedInstanceID,
		)
		r.UserManagedEC2Key = validation
		if err != nil {
			diagnosis := cpaws.DiagnoseUserManagedEC2Key(err)
			r.FailActionable(
				"aws-key-pair",
				"caller-owned EC2 SSH key is not ready",
				err.Error(),
				diagnosis.FailureClass,
				diagnosis.Field,
				diagnosis.Remediation,
			)
			return
		}
		r.Pass("aws-key-pair", validation.Summary())
	}
	r.Pass(
		"aws-iam",
		fmt.Sprintf(
			"local AWS/IAM ready (owner=%s account=%s cp9-owner=%s cp9-session=%s %s)",
			result.Owner,
			result.Account,
			result.SessionTags[cpaws.TagOwner],
			result.SessionTags[cpaws.TagSession],
			sessionIAMPreflightProfileDetails(session.Target.AWS.IAM, profile),
		),
	)
	if session.Host.Mode == config.HostModeRemoteEC2K3d {
		effective := cpaws.EffectiveAWSConfig(&awsCfg, result)
		plan, err := doctorResolveRemoteImagePlan(
			ctx,
			&effective,
			session.Host.EC2.InstanceType,
			session.Target.Region,
		)
		if err != nil {
			failureClass := "aws-remote-image-plan-invalid"
			field := "host.ec2.instance_type"
			remediation := "verify EC2 DescribeInstanceTypes/DescribeImages and SSM GetParameter access in the target region, then rerun cp9 doctor"
			if diagnosis, ok := remoteimage.Diagnose(err); ok {
				failureClass = diagnosis.FailureClass
				field = diagnosis.Field
				remediation = diagnosis.Remediation
			}
			r.FailActionable(
				"aws-remote-image",
				"derived remote image plan is invalid",
				err.Error(),
				failureClass,
				field,
				remediation,
			)
			return
		}
		r.Pass(
			"aws-remote-image",
			fmt.Sprintf(
				"derived remote image ready (family=%s instance_type=%s architecture=%s ami=%s region=%s)",
				plan.Family,
				plan.InstanceType,
				plan.Architecture,
				plan.AMI,
				plan.Region,
			),
		)
		r.Checks[len(r.Checks)-1].Details = fmt.Sprintf(
			"parameter=%s\nroot_device_name=%s\nresolved_at=%s",
			plan.Parameter,
			plan.RootDeviceName,
			plan.ResolvedAt.UTC().Format(time.RFC3339),
		)
	}
}

func resolveRemoteImagePlan(
	ctx context.Context,
	cfg *awssdk.Config,
	instanceType, region string,
) (*remoteimage.Plan, error) {
	if cfg == nil {
		return nil, fmt.Errorf("AWS config is required for remote image validation")
	}
	resolver := &remoteimage.Resolver{
		EC2:    doctorNewRemoteImageEC2Client(*cfg),
		SSM:    doctorNewRemoteImageSSMClient(*cfg),
		Region: region,
	}
	return resolver.Resolve(ctx, instanceType)
}

func actionableIAMBlocker(field, expected, fix string, err error) string {
	return fmt.Sprintf(
		"%v\nfield: %s\nexpected: %s\nfix: %s",
		err,
		field,
		expected,
		fix,
	)
}

func sessionIAMPreflightProfile(iam config.SessionIAMConfig) string {
	if sourceProfile := strings.TrimSpace(iam.SourceProfile); sourceProfile != "" {
		return sourceProfile
	}
	return strings.TrimSpace(iam.Profile)
}

func sessionIAMContractFailureClass(err error) string {
	if err == nil {
		return "aws-iam-invalid"
	}
	msg := err.Error()
	switch {
	case strings.Contains(msg, "cp9-owner"):
		return "owner-unresolved"
	case strings.Contains(msg, "AssumeRole"), strings.Contains(msg, "assume"):
		return "aws-role-assume-failed"
	default:
		return "aws-iam-invalid"
	}
}

func sessionIAMPreflightProfileDetails(iam config.SessionIAMConfig, profile string) string {
	runtimeProfile := strings.TrimSpace(iam.Profile)
	if runtimeProfile == "" || runtimeProfile == profile {
		return fmt.Sprintf("profile=%q", profile)
	}
	return fmt.Sprintf("source_profile=%q runtime_profile=%q", profile, runtimeProfile)
}

func runSSHWithTimeout(selected *host.Session, argv ...string) error {
	ctx, cancel := context.WithTimeout(context.Background(), doctorTimeout(selected))
	defer cancel()
	_, err := doctorRunSSH(ctx, selected, nil, argv...)
	return err
}

func doctorTimeout(selected *host.Session) time.Duration {
	if selected != nil && selected.IsRemote() {
		return host.SSHTimeout(selected)
	}
	return doctorCommandTimeout
}

// CheckRemoteDocker verifies that remote host-mode image builds can reach the
// Docker daemon on the remote EC2 host.
func CheckRemoteDocker(r *Result, selected *host.Session) bool {
	if selected == nil || selected.Mode != config.HostModeRemoteEC2K3d || selected.Remote == nil {
		return false
	}
	if err := runSSHWithTimeout(selected, "docker", "info"); err != nil {
		r.FailActionable(
			"remote-docker",
			"remote EC2 Docker daemon is not reachable",
			err.Error(),
			"remote-docker-unreachable",
			"host.remote.docker",
			"verify Docker is installed and running on the remote EC2 host before rerunning doctor",
		)
		return false
	}
	r.Pass("remote-docker", "remote EC2 Docker daemon is reachable")
	return true
}

// CheckRemoteK3d verifies the remote k3d runtime is reachable through the
// persisted remote host contract.
func CheckRemoteK3d(r *Result, selected *host.Session) {
	if selected == nil || selected.Mode != config.HostModeRemoteEC2K3d {
		return
	}
	if selected.Remote == nil {
		r.WarnActionable(
			"remote-k3d",
			"remote k3d runtime cannot be checked before remote host metadata exists",
			"run `cp9 up` once to provision the remote host",
			"remote-host-metadata-missing",
			"host.remote",
			"run `cp9 up` once to provision the remote host and persist host metadata",
		)
		return
	}
	clusterName := strings.TrimSpace(selected.ClusterName)
	if clusterName == "" {
		r.FailActionable(
			"remote-k3d",
			"remote k3d runtime contract is missing cluster name",
			"selected host has no cluster_name",
			"remote-k3d-unreachable",
			"host.cluster_name",
			"rerun `cp9 up` so the selected host contract records the remote k3d cluster name",
		)
		return
	}
	if err := runSSHWithTimeout(selected, "k3d", "cluster", "list", clusterName, "-o", "json"); err != nil {
		r.FailActionable(
			"remote-k3d",
			"remote k3d runtime is not reachable",
			err.Error(),
			"remote-k3d-unreachable",
			"host.remote.k3d",
			"verify the remote EC2 host, Docker daemon, and k3d cluster are running before rerunning doctor",
		)
		return
	}
	remoteKubeconfig := strings.TrimSpace(selected.Remote.RemoteKubeconfigPath)
	if remoteKubeconfig == "" {
		r.FailActionable(
			"remote-kubeconfig",
			"remote kubeconfig path is not recorded",
			"selected remote host has no remote_kubeconfig_path",
			"remote-kubeconfig-unreachable",
			"host.remote.remote_kubeconfig_path",
			"rerun `cp9 up` so the selected host contract records the remote kubeconfig path",
		)
		return
	}
	if err := runSSHWithTimeout(selected, "test", "-s", remoteKubeconfig); err != nil {
		r.FailActionable(
			"remote-kubeconfig",
			"remote kubeconfig is not reachable",
			err.Error(),
			"remote-kubeconfig-unreachable",
			"host.remote.remote_kubeconfig_path",
			"verify the remote kubeconfig exists on the EC2 host before rerunning doctor",
		)
		return
	}
	localKubeconfig := strings.TrimSpace(selected.KubeconfigPath)
	if localKubeconfig == "" {
		r.FailActionable(
			"remote-kube-tunnel",
			"local kubeconfig path for the remote API tunnel is not recorded",
			"selected host has no kubeconfig_path",
			"remote-tunnel-unreachable",
			"host.kubeconfig_path",
			"rerun `cp9 up` so the local controller has a kubeconfig for the remote k3d API tunnel",
		)
		return
	}
	if _, err := os.Stat(localKubeconfig); err != nil {
		r.FailActionable(
			"remote-kube-tunnel",
			"local kubeconfig for the remote API tunnel is not reachable",
			err.Error(),
			"remote-tunnel-unreachable",
			"host.kubeconfig_path",
			"restart the remote kube API tunnel or rerun `cp9 up` to refresh the local kubeconfig",
		)
		return
	}
	r.Pass("remote-k3d", fmt.Sprintf("remote k3d cluster %q is reachable", clusterName))
}

// CheckPremiumRemoteBuildContract verifies that Premium remote host mode keeps
// source sync, private module download, and image import on the remote host.
func CheckPremiumRemoteBuildContract(r *Result, session *config.SessionConfig, selected *host.Session) {
	if session == nil || session.APIVersion != config.APIVersionV1Alpha2 ||
		config.SessionPersona(session) != "dev-full" ||
		selected == nil || selected.Mode != config.HostModeRemoteEC2K3d {
		return
	}
	// Only the session-owned input is checked here. The remote build wrapper and
	// driver are files shipped in this repository, so asserting their contents at
	// runtime would tell an operator to "restore" a tracked file they cannot fix
	// from their session. AGENTS.md keeps constraints that are verifiable at
	// build, test or review time out of runtime paths.
	if _, err := cptilt.SelectedSourceBuildServices(session.Tilt.File); err != nil {
		r.FailActionable(
			"premium-remote-build",
			"Session Tiltfile source-build selection is not readable",
			err.Error(),
			"source-sync-failed",
			"tilt.file",
			"restore the configured Session Tiltfile before rerunning doctor",
		)
		return
	}
	r.Pass(
		"premium-remote-build",
		"Session Tiltfile source-build selection is readable",
	)
}
