package features

import (
	v3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3"
	"github.com/rancher/rancher/pkg/controllers/management/imported"
	managementv3 "github.com/rancher/rancher/pkg/generated/controllers/management.cattle.io/v3"
	v1 "github.com/rancher/wrangler/v3/pkg/generated/controllers/apiextensions.k8s.io/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var (
	t = true
)

func MigrateFeatures(featuresClient managementv3.FeatureClient, crdClient v1.CustomResourceDefinitionClient, mgmtClusterClient managementv3.ClusterClient) error {
	features, err := featuresClient.List(metav1.ListOptions{})
	if err != nil {
		return err
	}
	if len(features.Items) == 0 {
		return nil
	}

	hasLegacy := false
	for _, feature := range features.Items {
		switch feature.Name {
		case Legacy.Name():
			hasLegacy = true
		case MCM.Name():
			if err := enableMCMIfPreviouslyEnabled(&feature, featuresClient, crdClient); err != nil {
				return err
			}
		case RKE2.Name():
			if err := enableRKE2IfClustersExist(&feature, featuresClient, mgmtClusterClient); err != nil {
				return err
			}
		}
	}

	if !hasLegacy {
		_, err = featuresClient.Create(&v3.Feature{
			ObjectMeta: metav1.ObjectMeta{
				Name: Legacy.Name(),
			},
			Spec: v3.FeatureSpec{
				Value: &t,
			},
		})
		return err
	}

	return nil
}

func enableMCMIfPreviouslyEnabled(feature *v3.Feature, featuresClient managementv3.FeatureClient, crdClient v1.CustomResourceDefinitionClient) error {
	if feature.Spec.Value == nil || *feature.Spec.Value {
		return nil
	}

	_, err := crdClient.Get("nodes.management.cattle.io", metav1.GetOptions{})
	if apierrors.IsNotFound(err) {
		return nil
	} else if err != nil {
		return err
	}

	return SetFeature(featuresClient, MCM.Name(), true)
}

func enableRKE2IfClustersExist(feature *v3.Feature, featuresClient managementv3.FeatureClient, mgmtClusterClient managementv3.ClusterClient) error {
	if feature.Spec.Value == nil || *feature.Spec.Value {
		return nil
	}

	clusters, err := mgmtClusterClient.List(metav1.ListOptions{})
	if err != nil {
		return err
	}

	for _, c := range clusters.Items {
		if imported.IsAdministratedByProvisioningCluster(&c) {
			feature = feature.DeepCopy()
			feature.Spec.Value = &[]bool{true}[0]
			feature.Status.LockedValue = feature.Spec.Value

			_, err = featuresClient.Update(feature)
			return err
		}
	}

	return nil
}
