package cluster

import (
	"testing"

	"github.com/onsi/gomega"
	"github.com/samber/lo"

	bffclusterv1beta1 "github.com/tidbcloud/tidb-management-service/api/spec/bff/cluster_management/v1beta1"
	openapidedicatedv1beta1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/dedicated/v1beta1"
)

func TestAdvancedModifyRewriteClusterRequest(t *testing.T) {
	g := gomega.NewWithT(t)

	cluster := &openapidedicatedv1beta1.Cluster{
		ClusterId: "123",
		TidbNodeSetting: &openapidedicatedv1beta1.Cluster_TidbNodeSetting{
			TidbNodeGroups: []*openapidedicatedv1beta1.TidbNodeGroup{
				{
					TidbNodeGroupId: "1",
					NodeCount:       1,
				},
				{
					TidbNodeGroupId: "2",
					NodeCount:       2,
				},
			},
		},
		TikvNodeSetting: &openapidedicatedv1beta1.Cluster_StorageNodeSetting{
			NodeCount: 3,
		},
	}

	t.Run("only update tg", func(t *testing.T) {
		req := &bffclusterv1beta1.AdvancedModifyDedicatedClusterRequest_Cluster{
			TidbNodeSetting: &bffclusterv1beta1.AdvancedModifyDedicatedClusterRequest_TidbNodeSetting{
				NodeSpecKey: "4c8g",
				UpdateTidbNodeGroups: []*bffclusterv1beta1.AdvancedModifyDedicatedClusterRequest_TidbNodeGroupUpdate{
					{
						TidbNodeGroupId: "2",
						NodeCount:       20,
					},
				},
			},
		}

		nCluster, updated, err := buildValidateOnlyRequest(cluster, req)
		g.Expect(updated).Should(gomega.BeTrue())
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(len(nCluster.Cluster.TidbNodeSetting.TidbNodeGroups)).Should(gomega.Equal(2))

		tidbGroup, ok := lo.Find(
			nCluster.Cluster.TidbNodeSetting.TidbNodeGroups,
			func(item *openapidedicatedv1beta1.UpdateClusterRequest_TidbNodeSetting_TidbNodeGroup) bool {
				return item.TidbNodeGroupId == "1"
			},
		)
		g.Expect(ok).Should(gomega.BeTrue())
		g.Expect(tidbGroup.TidbNodeGroupId).Should(gomega.Equal("1"))
		g.Expect(tidbGroup.NodeCount).Should(gomega.Equal(lo.ToPtr(int32(1))))

		tidbGroup, ok = lo.Find(
			nCluster.Cluster.TidbNodeSetting.TidbNodeGroups,
			func(item *openapidedicatedv1beta1.UpdateClusterRequest_TidbNodeSetting_TidbNodeGroup) bool {
				return item.TidbNodeGroupId == "2"
			},
		)
		g.Expect(ok).Should(gomega.BeTrue())
		g.Expect(tidbGroup.TidbNodeGroupId).Should(gomega.Equal("2"))
		g.Expect(tidbGroup.NodeCount).Should(gomega.Equal(lo.ToPtr(int32(20))))
	})

	t.Run("create new tg", func(t *testing.T) {
		req := &bffclusterv1beta1.AdvancedModifyDedicatedClusterRequest_Cluster{
			TidbNodeSetting: &bffclusterv1beta1.AdvancedModifyDedicatedClusterRequest_TidbNodeSetting{
				NodeSpecKey: "4c8g",
				CreateTidbNodeGroups: []*bffclusterv1beta1.AdvancedModifyDedicatedClusterRequest_TidbNodeGroupCreate{
					{
						NodeCount: 30,
					},
				},
			},
		}

		nCluster, updated, err := buildValidateOnlyRequest(cluster, req)
		g.Expect(updated).Should(gomega.BeTrue())
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(len(nCluster.Cluster.TidbNodeSetting.TidbNodeGroups)).Should(gomega.Equal(2))

		count := lo.SumBy(
			nCluster.Cluster.TidbNodeSetting.TidbNodeGroups,
			func(item *openapidedicatedv1beta1.UpdateClusterRequest_TidbNodeSetting_TidbNodeGroup) int32 {
				return item.GetNodeCount()
			},
		)

		g.Expect(count).Should(gomega.Equal(int32(33)))
	})

	t.Run("delete tg", func(t *testing.T) {
		req := &bffclusterv1beta1.AdvancedModifyDedicatedClusterRequest_Cluster{
			TidbNodeSetting: &bffclusterv1beta1.AdvancedModifyDedicatedClusterRequest_TidbNodeSetting{
				DeleteTidbNodeGroupIds: []string{
					"2",
				},
			},
		}

		_, updated, err := buildValidateOnlyRequest(cluster, req)
		g.Expect(updated).Should(gomega.BeFalse())
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
	})

	t.Run("mix tg", func(t *testing.T) {
		req := &bffclusterv1beta1.AdvancedModifyDedicatedClusterRequest_Cluster{
			TidbNodeSetting: &bffclusterv1beta1.AdvancedModifyDedicatedClusterRequest_TidbNodeSetting{
				NodeSpecKey: "4c8g",
				DeleteTidbNodeGroupIds: []string{
					"2",
				},
				UpdateTidbNodeGroups: []*bffclusterv1beta1.AdvancedModifyDedicatedClusterRequest_TidbNodeGroupUpdate{
					{
						TidbNodeGroupId: "1",
						NodeCount:       10,
					},
				},
				CreateTidbNodeGroups: []*bffclusterv1beta1.AdvancedModifyDedicatedClusterRequest_TidbNodeGroupCreate{
					{
						NodeCount: 30,
					},
				},
			},
		}

		nCluster, updated, err := buildValidateOnlyRequest(cluster, req)
		g.Expect(updated).Should(gomega.BeTrue())
		g.Expect(err).ShouldNot(gomega.HaveOccurred())
		g.Expect(len(nCluster.Cluster.TidbNodeSetting.TidbNodeGroups)).Should(gomega.Equal(1))
		g.Expect(nCluster.Cluster.TidbNodeSetting.TidbNodeGroups[0].TidbNodeGroupId).Should(gomega.Equal("1"))
		g.Expect(nCluster.Cluster.TidbNodeSetting.TidbNodeGroups[0].NodeCount).
			Should(gomega.Equal(lo.ToPtr(int32(40))))
	})
}
