package cmd

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"time"

	"cloud.google.com/go/pubsub"
	"github.com/aws/aws-sdk-go/aws/session"
	opbrv2 "github.com/pingcap/tidb-operator/api/v2/br/v1alpha1"
	opv2 "github.com/pingcap/tidb-operator/api/v2/core/v1alpha1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/types"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"sigs.k8s.io/aws-iam-authenticator/pkg/token"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/cache"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/manager"
	"sigs.k8s.io/controller-runtime/pkg/predicate"

	"github.com/tidbcloud/eks-provider/controllers/backup"
	"github.com/tidbcloud/eks-provider/controllers/cluster"
	commontask "github.com/tidbcloud/eks-provider/controllers/cluster/task/common"
	"github.com/tidbcloud/eks-provider/controllers/cluster/task/gke/nodetag"
	"github.com/tidbcloud/eks-provider/controllers/compactbackup"
	"github.com/tidbcloud/eks-provider/controllers/configchange"
	cloudhibernation "github.com/tidbcloud/eks-provider/controllers/hibernation"
	"github.com/tidbcloud/eks-provider/controllers/k8sversion"
	"github.com/tidbcloud/eks-provider/controllers/network"
	networkmanager "github.com/tidbcloud/eks-provider/controllers/network/manager"
	"github.com/tidbcloud/eks-provider/controllers/networkpeer"
	"github.com/tidbcloud/eks-provider/controllers/replay"
	"github.com/tidbcloud/eks-provider/controllers/restore"
	"github.com/tidbcloud/eks-provider/controllers/upgradeoperation"
	"github.com/tidbcloud/eks-provider/controllers/utils/clinic_event"
	"github.com/tidbcloud/eks-provider/controllers/utils/configmanager"
	"github.com/tidbcloud/eks-provider/controllers/utils/maxtimes"
	"github.com/tidbcloud/eks-provider/controllers/workflow"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-provider/pkg/account"
	accountsched "github.com/tidbcloud/infra-provider/pkg/account/schedule"
	accountschedpl "github.com/tidbcloud/infra-provider/pkg/account/schedule/plugin"
	"github.com/tidbcloud/infra-provider/pkg/cloud/aws"
	"github.com/tidbcloud/infra-provider/pkg/cloud/gcp"
	pkgconfig "github.com/tidbcloud/infra-provider/pkg/config"
	"github.com/tidbcloud/infra-provider/pkg/consts"
	"github.com/tidbcloud/infra-provider/pkg/dataplane"
	"github.com/tidbcloud/infra-provider/pkg/hibernation"
	"github.com/tidbcloud/infra-provider/pkg/k8s"
	"github.com/tidbcloud/infra-provider/pkg/metrics"
	"github.com/tidbcloud/infra-provider/pkg/nodegroup/selfmanaged"
	"github.com/tidbcloud/infra-provider/pkg/procedure"
	"github.com/tidbcloud/infra-provider/pkg/scheme"
	"github.com/tidbcloud/infra-provider/pkg/taskevents"
	"github.com/tidbcloud/infra-provider/pkg/tracer"
	utiltime "github.com/tidbcloud/infra-provider/pkg/util/time"
	// +kubebuilder:scaffold:imports
)

func init() {
	// install the TiDB Operator scheme here instead of in the "pkg" mod
	// to avoid importing the TiDB Operator go mod for too many projects
	utilruntime.Must(opv2.Install(scheme.Scheme))
	utilruntime.Must(opbrv2.Install(scheme.Scheme))
}

func buildCMCacheConfig(selector labels.Selector) map[client.Object]cache.ByObject {
	return map[client.Object]cache.ByObject{
		&cloudv1.Network{}: {
			Label: selector,
		},
		&cloudv1.Cluster{}: {
			Label: selector,
		},
		&cloudv1.NetworkPeer{}: {
			Label: selector,
		},
		&cloudv1.UpgradeOperation{}: {
			Label: selector,
		},
	}
}

func mustRegisterCMControllers(rootConfig pkgconfig.RootConfig, mgr ctrl.Manager, mt maxtimes.MaxTimes) {
	setupLog.Info("loading base kubeconfig for cm controllers")

	p, err := predicate.LabelSelectorPredicate(rootConfig.Predicate)
	if err != nil {
		setupLog.Error(err, "unable to create predicate")
		os.Exit(1)
	}

	awsCli, err := initAWSClientSet()
	if err != nil {
		setupLog.Error(err, "failed to init aws client")
		os.Exit(1)
	}

	var (
		gcpCli gcp.Client
	)
	providerType := rootConfig.Predicate.MatchLabels[cloudv1.ProviderTypeLabel]
	if providerType == consts.ProviderTypeEKS {
		// dynamic set regional AMIIDs
		if err := populateWorkerNodeAMIConfig(&rootConfig, awsCli); err != nil {
			setupLog.Error(err, "failed to populate AMI config")
		}
		setupLog.Info("will use these AMIIDs for worker nodes", "x86", rootConfig.AMIConfig.X86AMIIDs, "arm", rootConfig.AMIConfig.ARMAMIIDs)
	} else if providerType == consts.ProviderTypeGKE {
		gcpCli, err = gcp.NewClientSet()
		if err != nil {
			setupLog.Error(err, "failed to init gcp client")
			os.Exit(1)
		}
	} else if providerType == consts.ProviderTypeACK {
		setupLog.Info("running with ACK provider")
	}

	if controllerEnabled(K8sVersionController) {
		setupLog.Info("enable k8s version controller only")
		if err := k8sversion.NewReconciler(mgr.GetClient(), mgr.GetCache(), awsCli, gcpCli, &rootConfig, utiltime.RealClock{}, mgr.GetEventRecorderFor("upgradeoperation-controller")).SetupWithManager(mgr, p); err != nil {
			setupLog.Error(err, "unable to create controller", "controller", "K8sVersion")
			os.Exit(1)
		}
		return
	}

	// TODO: skip reconcile this when running in debug mode
	var topicCli *pubsub.Topic
	if taskevents.IsEnabled(rootConfig) {
		ctx := context.Background()
		pubSubClient, err := pubsub.NewClient(ctx, rootConfig.TaskEvents.ProjectID)
		if err != nil {
			panic(err)
		}
		topicCli = pubSubClient.Topic(rootConfig.TaskEvents.TopicID)
	}

	var accountInfoGetter *account.Info
	if controllerEnabled(ClusterController) || controllerEnabled(NetworkController) {
		if err := rootConfig.FullManage.Info.Valid(rootConfig.Provider); err != nil {
			// Just let accountSelector be nil and panic when use it if failed to setup since
			// it is not required for not full manager now.
			setupLog.Error(err, "failed to setup accountSelector will not able to run full manager")
			os.Exit(1)
		}
	}

	accountInfoGetter = &rootConfig.FullManage.Info

	sess := session.Must(session.NewSession())
	setupLog.Info("setting up dataplane k8s manager")
	dataplaneReconcilerRegister := []k8s.DataplaneReconcilerRegister{}
	// NodeProtector will try to update all nodes within a dataplane k8s, in other words, try to update some nodes are created by
	// another non-Running clusters and cause insufficient privileges errors. So we disable it in dryrun mode.
	if providerType == consts.ProviderTypeEKS && !rootConfig.DryRun.Enabled {
		// cluster node protector register
		npr := networkmanager.NewClusterNodeProtectorRegister(mgr.GetClient(), procedure.NewAWSService(sess), rootConfig)
		dataplaneReconcilerRegister = append(dataplaneReconcilerRegister, npr)
	}
	if providerType == consts.ProviderTypeGKE && !rootConfig.DryRun.Enabled {
		ntr := nodetag.NewClusterNodeTaggerRegister(mgr.GetClient(), gcpCli, rootConfig)
		dataplaneReconcilerRegister = append(dataplaneReconcilerRegister, ntr)
	}

	k8sManager := k8s.NewManager(mgr.GetClient(), dataplaneReconcilerRegister, scheme.Scheme)
	go func() {
		err := <-k8sManager.Errors()
		setupLog.Error(err, "network manager error")
		os.Exit(1)
	}()
	envProviderManager := dataplane.NewEnvProviderManager(scheme.Scheme, mgr.GetClient(), &dataplane.EnvProviderManagerOptions{
		Dryrun:                 rootConfig.DryRun.Enabled,
		AssumeRoleName:         rootConfig.FullManage.AssumeRoleName,
		ReadonlyAssumeRoleName: rootConfig.FullManage.ReadonlyAssumeRoleName,
		AssumeRoleExternalID:   rootConfig.FullManage.AssumeRoleExternalID,
		DataplaneKubeconfig:    rootConfig.ClusterController.DataplaneKubeconfig,
	})

	// add background scale-protection checker for AWS self-managed nodegroups
	if providerType == consts.ProviderTypeEKS && !rootConfig.DryRun.Enabled {
		checker := &commontask.ScaleProtectionChecker{
			InfraClient:          mgr.GetClient(),
			EnvProviderManager:   envProviderManager,
			Logger:               ctrl.Log.WithName("scale-protection-checker"),
			AWSCli:               awsCli,
			AssumeRoleName:       rootConfig.FullManage.AssumeRoleName,
			AssumeRoleExternalID: rootConfig.FullManage.AssumeRoleExternalID,
		}
		if err := mgr.Add(checker); err != nil {
			setupLog.Error(err, "unable to add scale protection checker")
			os.Exit(1)
		}
	}
	if controllerEnabled(NetworkController) {
		setupLog.Info("enable network controller")
		rootConfig.Network.SelfSignedCAConfig.InitTiDBServerSelfSignedCAData()
		mustRegisterNetworkControllers(rootConfig, accountInfoGetter, awsCli, gcpCli, topicCli, k8sManager, mgr)
	} else if controllerEnabled(UOController) {
		setupLog.Info("enable UpgradeOperation controller")
		// UpgradeOperation controller is only used to upgrade tidb nodes in 3-layer arch.
		if err = upgradeoperation.NewReconciler(envProviderManager, mgr.GetClient(), mgr.GetCache(), awsCli, gcpCli, &rootConfig, utiltime.RealClock{}, mgr.GetEventRecorderFor("UpgradeOperation-controller")).SetupWithManager(mgr, p); err != nil {
			setupLog.Error(err, "unable to create controller", "controller", "UpgradeOperation")
			os.Exit(1)
		}
	}

	proxyAuthFunc, err := initProxyAuth(rootConfig)
	if err != nil {
		setupLog.Error(err, "unable to get token using given proxy auth0 credentials, please check envs")
		os.Exit(1)
	}

	configManager := configmanager.NewConfigManager(mgr.GetClient(), pkgconfig.PreConfigKeys, &rootConfig)
	if controllerEnabled(ClusterController) {
		err := validateAuditConfig(rootConfig.Override, rootConfig.ClusterController.Audit)
		if err != nil {
			setupLog.Error(err, "unable to set up audit log")
			os.Exit(1)
		}
		if err = (&cluster.ClusterReconciler{
			Client:              mgr.GetClient(),
			LegacyManager:       k8sManager,
			CachedProvider:      envProviderManager,
			Cache:               mgr.GetCache(),
			ConfigManager:       configManager,
			Config:              rootConfig,
			CloudConfigProvider: &rootConfig,
			Logger:              ctrl.Log.WithName("controllers").WithName("Cluster"),
			AcctInfoGetter:      accountInfoGetter,
			PDAuthFunc:          proxyAuthFunc,
			AWSCli:              awsCli,
			GCPCli:              gcpCli,
			EventRecorder:       mgr.GetEventRecorderFor("cluster-controller"),
			TopicCli:            topicCli,
			MaxTimes:            mt,
		}).SetupWithManager(mgr, p); err != nil {
			setupLog.Error(err, "unable to create controller", "controller", "Cluster")
			os.Exit(1)
		}
	}

	if controllerEnabled(ConfigChangeController) {
		// clinic event
		if activity := rootConfig.ClusterController.ConfigChange.Activity; activity.Enabled {
			setupLog.Info("clinic activity is enabled")
			token := os.Getenv(pkgconfig.EnvKeyClinicActivityToken)
			if token == "" {
				panic("clinic activity token is required")
			}
			if err := clinic_event.InitEventClient(
				activity.ActivityHubEndpoint,
				activity.ActivityHubSource,
				activity.ActivityHubSourceKey,
				activity.ClinicEndpoint,
				token,
			); err != nil {
				setupLog.Error(err, "unable to init clinic event")
				os.Exit(1)
			}
		}
		if err = configchange.NewConfigChangeReconciler(
			mgr,
			envProviderManager,
			ctrl.Log.WithName("controllers").WithName("ConfigChange"),
			rootConfig,
		).SetupWithManager(mgr, p); err != nil {
			setupLog.Error(err, "unable to create controller", "controller", "ConfigChange")
			os.Exit(1)
		}
	}

	if controllerEnabled(BackupController) {
		// new backup controller
		backupReconciler := backup.Reconciler{
			Logger:             ctrl.Log.WithName("controllers").WithName("Backup"),
			EventRecorder:      mgr.GetEventRecorderFor("backup-controller"),
			Client:             mgr.GetClient(),
			Cache:              mgr.GetCache(),
			CachedRemoteClient: envProviderManager,
			Config:             rootConfig.BR,
			RootConfig:         rootConfig,
		}
		if err := backupReconciler.SetupWithManager(mgr, p); err != nil {
			setupLog.Error(err, "unable to create controller", "controller", "New Backup")
			os.Exit(1)
		}
	}

	if controllerEnabled(CompactBackupController) {
		// CompactBackup controller
		compactBackupReconciler := compactbackup.Reconciler{
			Logger:             ctrl.Log.WithName("controllers").WithName("CompactBackup"),
			EventRecorder:      mgr.GetEventRecorderFor("compactbackup-controller"),
			Client:             mgr.GetClient(),
			Cache:              mgr.GetCache(),
			CachedRemoteClient: envProviderManager,
			Config:             rootConfig.BR,
			RootConfig:         rootConfig,
		}
		if err := compactBackupReconciler.SetupWithManager(mgr, p); err != nil {
			setupLog.Error(err, "unable to create controller", "controller", "CompactBackup")
			os.Exit(1)
		}
	}

	if controllerEnabled(RestoreController) {
		// new restore controller
		restoreReconciler := restore.Reconciler{
			Logger:             ctrl.Log.WithName("controllers").WithName("Restore"),
			EventRecorder:      mgr.GetEventRecorderFor("restore-controller"),
			Client:             mgr.GetClient(),
			Cache:              mgr.GetCache(),
			CachedRemoteClient: envProviderManager,
			Config:             rootConfig.BR,
			RootConfig:         rootConfig,
		}
		if err := restoreReconciler.SetupWithManager(mgr, p); err != nil {
			setupLog.Error(err, "unable to create controller", "controller", "New Restore")
			os.Exit(1)
		}
	}

	if controllerEnabled(WorkflowController) {
		// setup workflow controller
		if err = workflow.NewWorkflowReconciler(
			mgr,
			envProviderManager,
			ctrl.Log.WithName("controllers").WithName("Workflow"),
			utiltime.RealClock{},
			gcpCli,
			workflow.WithPDAuth(proxyAuthFunc),
			workflow.WithDryRun(rootConfig.DryRun.Enabled),
			workflow.WithAWSCli(awsCli),
			workflow.WithAWSAssumeRole(rootConfig.FullManage.AssumeRoleName, rootConfig.FullManage.AssumeRoleExternalID),
			workflow.WithPDServiceResolver(func(cluster *cloudv1.Cluster) types.NamespacedName {
				serviceName := "proxy-cluster-proxy"
				if pkgconfig.FeatureEnabled(rootConfig.FeatureGates, pkgconfig.UseProxyGatewayIngress, cluster.GetTenantID(), cluster.GetProjectID()) {
					serviceName = "clustergateway-kong-proxy"
				}
				return types.NamespacedName{
					Namespace: "tidb-admin",
					Name:      serviceName,
				}
			}),
		).SetupWithManager(mgr, p); err != nil {
			setupLog.Error(err, "unable to create controller", "controller", "Workflow")
			os.Exit(1)
		}
	}

	if controllerEnabled(ReplayController) {
		replayReconciler := replay.Reconciler{
			Logger:        ctrl.Log.WithName("controllers").WithName("Replay"),
			EventRecorder: mgr.GetEventRecorderFor("replay-controller"),
			Client:        mgr.GetClient(),
			Cache:         mgr.GetCache(),
			Manager:       dataplane.NewK8sClientManager(scheme.Scheme),
			RootConfig:    rootConfig,
		}
		if err := replayReconciler.SetupWithManager(mgr, p); err != nil {
			setupLog.Error(err, "unable to create controller", "controller", "Replay")
			os.Exit(1)
		}
	}
}

// runCMControllers is the entrypoint for the CM(tidb-cluster-management) controllers
func RunCMControllers() {
	tracer.InitTracer(setupLog, consts.ServiceName)

	rootConfig := mustBuildRootConfig()
	if DryRun {
		rootConfig.DryRun.Enabled = DryRun
	}
	if rootConfig.DryRun.Enabled {
		setupLog.Info("Run in dryrun mode")

		// disable configchange activity
		rootConfig.ClusterController.ConfigChange.Activity.Enabled = false
		// disable task event
		rootConfig.TaskEvents.TopicID = ""
	}

	// parse cache selector from root config
	selector, err := metav1.LabelSelectorAsSelector(&rootConfig.Predicate)
	if err != nil {
		setupLog.Error(err, "invalid predicates")
		os.Exit(1)
	}
	mgr := mustBuildManager("cluster", rootConfig.Network.Region, buildCMCacheConfig(selector), nil, rootConfig.DryRun.Enabled)
	mt := maxtimes.NewMaxTimes(ctrl.Log.WithName("maxtimes"))
	mustRegisterCMControllers(rootConfig, mgr, mt)
	ctx, cancel := context.WithCancel(ctrl.SetupSignalHandler())
	defer cancel()

	if rootConfig.DryRun.Enabled {
		if err := mgr.Add(manager.RunnableFunc(func(ctx context.Context) error {
			go mt.Run(ctx, func() {
				{
					result := "passed"
					if len(mt.KeysExceedMaxTimes()) != 0 {
						result = "failed"
					}
					metrics.ControllerPrereleaseJob.With(map[string]string{
						"controller": "cluster",
						"provider":   rootConfig.Provider,
						"region":     rootConfig.Network.Region,
						"result":     result,
					}).Set(1)
					setupLog.Info("#### dryrun finished", "result", result, "failed_keys", mt.KeysExceedMaxTimes())

					// wait for all metrics are scraped
					time.Sleep(time.Minute * 3)
				}

				cancel()
			})

			return nil
		})); err != nil {
			setupLog.Error(err, "cannot add max times limiter")
			os.Exit(1)
		}
	}

	mustRunManager(ctx, mgr)
	if rootConfig.DryRun.Enabled {
		setupLog.Info("manager stopped, run a dummy http server to serve healthz and readyz endpoints.")
		// Continue to run as a long-running process to make dryrun task can be deployed as a deployment.
		// When go here, the manager is already stopped, so it shouldn't have any load on the apiserver.

		// Run a simple HTTP server to serve healthz and readyz endpoints
		mux := http.NewServeMux()
		mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(http.StatusOK)
			_, _ = w.Write([]byte("ok"))
		})
		mux.HandleFunc("/readyz", func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(http.StatusOK)
			_, _ = w.Write([]byte("ok"))
		})
		if err := http.ListenAndServe(probeAddr, mux); err != nil {
			setupLog.Error(err, "failed to start health check server")
		}
	}
}

func mustRegisterNetworkControllers(rootConfig pkgconfig.RootConfig, accountInfoGetter *account.Info, awsCli aws.Client, gcpCli gcp.Client, topicCli *pubsub.Topic, k8sManager *k8s.Manager, mgr ctrl.Manager) {
	p, err := predicate.LabelSelectorPredicate(rootConfig.Predicate)
	if err != nil {
		setupLog.Error(err, "unable to create predicate")
		os.Exit(1)
	}
	providerType := rootConfig.Predicate.MatchLabels[cloudv1.ProviderTypeLabel]
	accountScheduler, err := accountsched.NewScheduler(&rootConfig.AccountScheduler, accountschedpl.NewDefaultRegistry())
	if err != nil {
		setupLog.Error(err, "unable to create account scheduler")
		os.Exit(1)
	}

	tokenGen, err := token.NewGenerator(false, false)
	if err != nil {
		setupLog.Error(err, "unable to create k8s token generator")
		os.Exit(1)
	}

	if err = (&network.NetworkReconciler{
		Client:         mgr.GetClient(),
		Cache:          mgr.GetCache(),
		Scheme:         mgr.GetScheme(),
		TokenGen:       tokenGen,
		Config:         rootConfig,
		Provider:       providerType,
		Logger:         ctrl.Log.WithName("controllers").WithName("Network"),
		AcctInfoGetter: accountInfoGetter,
		AcctScheduler:  accountScheduler,
		Manager:        k8sManager,
		AWS:            awsCli,
		GCP:            gcpCli,
		EventRecorder:  mgr.GetEventRecorderFor("network-controller"),
		TopicCli:       topicCli,
	}).SetupWithManager(mgr, p); err != nil {
		setupLog.Error(err, "unable to create controller", "controller", "Network")
		os.Exit(1)
	}

	if rootConfig.Hibernation.Enabled {
		helper := cloudhibernation.HibernationHelper{
			GcpCli: gcpCli,
		}
		hc := hibernation.NewCloudProviderHibernationController(mgr.GetClient(), mgr.GetEventRecorderFor("hibernation-controller"), rootConfig.Predicate, cloudv1.Hibernation{
			CheckIdleInterval: rootConfig.Hibernation.CheckIdleInterval,
			IdleTimeThreshold: rootConfig.Hibernation.IdleTimeThreshold,
		}, helper.OnlyMasterWorker,
			rootConfig.EnabledNetworkHibernation,
		)
		hc.RunCloudProviderHibernationController()
	}

	if controllerEnabled(NetworkPeerController) {
		if err = (&networkpeer.NetworkPeerReconciler{
			Config:        rootConfig,
			InfraCli:      mgr.GetClient(),
			APIReader:     mgr.GetAPIReader(),
			Logger:        ctrl.Log.WithName("controllers").WithName("NetworkPeer"),
			EventRecorder: mgr.GetEventRecorderFor("networkpeer-controller"),
		}).SetupWithManager(mgr, p); err != nil {
			setupLog.Error(err, "unable to create controller", "controller", "NetworkPeer")
			os.Exit(1)
		}
	}
}

// populateWorkerNodeAMIConfig queries the worker node AMI IDs for x86 and arm64, then populate them into the config,
// which will be used for creating tidb clusters' self-managed nodegroups.
func populateWorkerNodeAMIConfig(cfg *pkgconfig.RootConfig, awsCli aws.Client) (err error) {
	ssmClient := awsCli.SSM(nil)

	hasLatestVersion := false
	for _, version := range cfg.AMIConfig.SupportedVersions {
		if version == cfg.Network.K8sVersion {
			hasLatestVersion = true
			break
		}
	}
	if !hasLatestVersion {
		cfg.AMIConfig.SupportedVersions = append(cfg.AMIConfig.SupportedVersions, cfg.Network.K8sVersion)
	}

	cfg.AMIConfig.X86AMIIDs = make(map[string]string)
	cfg.AMIConfig.ARMAMIIDs = make(map[string]string)

	for _, version := range cfg.AMIConfig.SupportedVersions {
		x86Name, armName := selfmanaged.GetSSMName(version, consts.AMD64ArchName), selfmanaged.GetSSMName(version, consts.ARM64ArchName)

		// Get the AMI ID for x86_64 architecture
		x86AMIID, err := aws.GetAMIID(context.TODO(), ssmClient, x86Name)
		if err != nil {
			return fmt.Errorf("failed to get Bottlerocket x86_64 AMI ID: %w", err)
		}
		cfg.AMIConfig.X86AMIIDs[version] = *x86AMIID

		// Get the AMI ID for ARM architecture
		armAMIID, err := aws.GetAMIID(context.TODO(), ssmClient, armName)
		if err != nil {
			return fmt.Errorf("failed to get Bottlerocket ARM AMI ID: %w", err)
		}
		cfg.AMIConfig.ARMAMIIDs[version] = *armAMIID

		// To be compatible with shared vpc
		if version == cfg.Network.K8sVersion {
			cfg.AMIConfig.X86AMIID = x86AMIID
			cfg.AMIConfig.ARMAMIID = armAMIID
		}
	}

	return nil
}
