package regionaction

import (
	"testing"
	"time"

	. "github.com/onsi/gomega"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	regionalv1 "github.com/tidbcloud/infra-provider/api/tidbcloud/regional-server/v1"

	opent "github.com/tidbcloud/devops/entity/operation"
)

func Test_upgradeO11yK8sNodes_buildRequest(t *testing.T) {
	tests := []struct {
		name     string
		instance *opent.Instance
		info     *regionalv1.K8SInformation
		want     *regionalv1.CreateUpgradeOperationRequest
		wantErr  string
	}{
		{
			name: "missing desired version",
			instance: &opent.Instance{
				ID:     123,
				Params: map[opent.ParamName]string{},
			},
			info:    &regionalv1.K8SInformation{AppboxName: "test-appbox"},
			wantErr: "desired_version is required",
		},
		{
			name: "successful request",
			instance: &opent.Instance{
				ID: 123,
				Params: map[opent.ParamName]string{
					opent.ParamDesiredVersion: "1.32",
				},
			},
			info: &regionalv1.K8SInformation{AppboxName: "test-appbox"},
			want: &regionalv1.CreateUpgradeOperationRequest{
				UpgradeOperation: &regionalv1.UpgradeOperation{
					Name:       "devops-upgradeo11yk8snodes-123",
					AppboxName: "test-appbox",
					Duration:   "2m",
					Ttl:        defaultTTL,
					Schedule:   time.Now().Add(1 * time.Minute).Format(cloudv1.UpgradeOperationScheduleLayout),
					Steps: []*regionalv1.UpgradeStep{
						{
							Target:  o11yK8sNodes,
							Version: "1.32",
						},
					},
				},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			g := NewGomegaWithT(t)
			a := &upgradeO11yK8sNodes{}
			got, err := a.buildRequest(tt.instance, tt.info)

			assertUpgradeO11yRequest(g, got, err, tt.want, tt.wantErr)
		})
	}
}

func Test_upgradeO11yTiDBNodes_buildRequest(t *testing.T) {
	tests := []struct {
		name     string
		instance *opent.Instance
		info     *regionalv1.K8SInformation
		want     *regionalv1.CreateUpgradeOperationRequest
		wantErr  string
	}{
		{
			name: "missing desired version",
			instance: &opent.Instance{
				ID:     123,
				Params: map[opent.ParamName]string{},
			},
			info:    &regionalv1.K8SInformation{AppboxName: "test-appbox"},
			wantErr: "desired_version is required",
		},
		{
			name: "missing cluster id",
			instance: &opent.Instance{
				ID: 123,
				Params: map[opent.ParamName]string{
					opent.ParamDesiredVersion: "1.32",
				},
			},
			info:    &regionalv1.K8SInformation{AppboxName: "test-appbox"},
			wantErr: "cluster_id is required",
		},
		{
			name: "successful request",
			instance: &opent.Instance{
				ID: 123,
				Params: map[opent.ParamName]string{
					opent.ParamDesiredVersion: "1.32",
					opent.ParamClusterID:      "123456789",
				},
			},
			info: &regionalv1.K8SInformation{AppboxName: "test-appbox"},
			want: &regionalv1.CreateUpgradeOperationRequest{
				UpgradeOperation: &regionalv1.UpgradeOperation{
					Name:       "devops-upgradeo11ytidbnodes-123",
					AppboxName: "test-appbox",
					Duration:   "2m",
					Ttl:        defaultTTL,
					Schedule:   time.Now().Add(1 * time.Minute).Format(cloudv1.UpgradeOperationScheduleLayout),
					Steps: []*regionalv1.UpgradeStep{
						{
							Target:    o11yTiDBNodes,
							Version:   "1.32",
							ClusterId: "123456789",
						},
					},
				},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			g := NewGomegaWithT(t)
			a := &upgradeO11yTiDBNodes{}
			got, err := a.buildRequest(tt.instance, tt.info)

			assertUpgradeO11yRequest(g, got, err, tt.want, tt.wantErr)
		})
	}
}

func assertUpgradeO11yRequest(g Gomega, got *regionalv1.CreateUpgradeOperationRequest, err error, want *regionalv1.CreateUpgradeOperationRequest, wantErr string) {
	if wantErr != "" {
		g.Expect(err).To(MatchError(ContainSubstring(wantErr)))
		g.Expect(got).To(BeNil())
		return
	}

	g.Expect(err).NotTo(HaveOccurred())
	gotOp := got.UpgradeOperation
	wantOp := want.UpgradeOperation

	g.Expect(gotOp.Name).To(Equal(wantOp.Name))
	g.Expect(gotOp.AppboxName).To(Equal(wantOp.AppboxName))
	g.Expect(gotOp.Duration).To(Equal(wantOp.Duration))
	g.Expect(gotOp.Ttl).To(Equal(wantOp.Ttl))
	g.Expect(gotOp.Steps).To(Equal(wantOp.Steps))

	schedule, err := time.Parse(cloudv1.UpgradeOperationScheduleLayout, gotOp.Schedule)
	g.Expect(err).NotTo(HaveOccurred())
	g.Expect(schedule.After(time.Now())).To(BeTrue())
	g.Expect(schedule.Before(time.Now().Add(2 * time.Minute))).To(BeTrue())
}
