package data

import (
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/utils/pointer"
	"sigs.k8s.io/controller-runtime/pkg/client"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
)

const (
	DefaultAWSInstanceType = "c6g.xlarge"
)

type ClusterPatch func(net *cloudv1.Cluster) *cloudv1.Cluster

func (p ClusterPatch) Patch(obj client.Object) client.Object {
	net, ok := obj.(*cloudv1.Cluster)
	if !ok {
		return obj
	}
	return p(net)
}

func NewDefaultCluster(net *cloudv1.Network) *cloudv1.Cluster {
	provider := net.Spec.Provider
	instanceType := DefaultAWSInstanceType
	return &cloudv1.Cluster{
		ObjectMeta: metav1.ObjectMeta{
			// TODO: refactor name
			Name:      net.Namespace,
			Namespace: net.Namespace,
			Labels: map[string]string{
				"cloud.pingcap.com/provider-type": provider,
				"cloud.pingcap.com/region":        net.Spec.Region,
				"tags.tidbcloud.com/cluster":      "test",
				"tags.tidbcloud.com/project":      net.Namespace,
				"tags.tidbcloud.com/servicetype":  "dedicated",
				"tags.tidbcloud.com/tenant":       defaultTenant,
			},
		},
		Spec: cloudv1.ClusterSpec{
			NetworkName: net.Name,
			SqlEndpoints: cloudv1.SqlEndpoints{
				Public: cloudv1.Service{
					Enabled: pointer.Bool(true),
					Port:    pointer.Int32(4000),
					LoadBalancerSourceRanges: []string{
						"0.0.0.0/0",
					},
				},
				Private: &cloudv1.Service{
					Enabled: pointer.Bool(true),
					Port:    pointer.Int32(4000),
				},
				PrivateLinkService: &cloudv1.PrivateLinkService{
					AWS: &cloudv1.AWSPrivateLinkService{
						AcceptedEndpoints: []string{},
					},
				},
			},
			Cluster: cloudv1.ClusterTopology{
				TiDB: cloudv1.TiDB{
					Replicas:     2,
					InstanceType: instanceType,
					Audit: &cloudv1.Audit{
						Enable: true,
					},
				},
				TiKV: cloudv1.TiKV{
					Replicas:         3,
					InstanceType:     instanceType,
					StorageClassName: "tikv-gp3-4000-400",
					StorageSize:      resource.MustParse("10Gi"),
				},
				PD: cloudv1.PD{
					Replicas:         3,
					InstanceType:     instanceType,
					StorageClassName: "pd-gp3-4000-400",
					StorageSize:      resource.MustParse("10Gi"),
				},
			},
		},
	}
}

func ClusterWithAllowedPrivateLinkEndpoints(endpoints ...string) ClusterPatch {
	return func(c *cloudv1.Cluster) *cloudv1.Cluster {
		c.Spec.SqlEndpoints.PrivateLinkService.AWS.AcceptedEndpoints = endpoints
		return c
	}
}

func ResetClusterStatus() ClusterPatch {
	return func(c *cloudv1.Cluster) *cloudv1.Cluster {
		c.Status = cloudv1.ClusterStatus{}

		return c
	}
}

func ResetClusterStatusPhaseToCreating() ClusterPatch {
	return func(c *cloudv1.Cluster) *cloudv1.Cluster {
		c.Status.Phase = cloudv1.ClusterPhaseCreating

		return c
	}
}

func ClusterWithExtraGroup() ClusterPatch {
	return func(c *cloudv1.Cluster) *cloudv1.Cluster {
		instanceType := DefaultAWSInstanceType
		c.Spec.ExtraGroups = append(c.Spec.ExtraGroups, cloudv1.ExtraGroupSpec{
			Name: "test",
			TiDB: cloudv1.TiDB{
				Replicas:     1,
				InstanceType: instanceType,
			},
			SqlEndpoints: cloudv1.SqlEndpoints{
				Public: cloudv1.Service{
					Enabled: pointer.Bool(true),
					Port:    pointer.Int32(4000),
					LoadBalancerSourceRanges: []string{
						"0.0.0.0/0",
					},
				},
			},
		})
		return c
	}
}
