package common

import (
	"testing"

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

	opv1alpha1 "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1"
)

func Test_expectToBeUpgraded(t *testing.T) {
	tests := []struct {
		name       string
		target     cloudv1.UpgradeOperationTarget
		desiredVer string
		curVer     string
		wantRet    bool
	}{
		{
			name:    "both empty",
			wantRet: false,
		},
		{
			name:    "desired version is empty",
			curVer:  "1.24",
			wantRet: false,
		},
		{
			name:       "current version is empty",
			desiredVer: "1.24",
			wantRet:    false,
		},
		{
			name:       "same version",
			target:     cloudv1.ControlPlane,
			desiredVer: "1.24",
			curVer:     "1.24",
			wantRet:    false,
		},
		{
			name:       "desired version is greater than current version 1",
			target:     cloudv1.ControlPlane,
			desiredVer: "1.25",
			curVer:     "1.24",
			wantRet:    true,
		},
		{
			name:       "ControlPlane: desired version is greater than current version 2",
			target:     cloudv1.ControlPlane,
			desiredVer: "1.26",
			curVer:     "1.24",
			wantRet:    false,
		},
		{
			name:       "AdminNodes: desired version is greater than current version 2",
			target:     cloudv1.AdminNodes,
			desiredVer: "1.26",
			curVer:     "1.24",
			wantRet:    true,
		},
		{
			name:       "desired version is less than current version 1",
			target:     cloudv1.AdminNodes,
			desiredVer: "1.24",
			curVer:     "1.25",
			wantRet:    false,
		},
		{
			name:       "desired version is less than current version 2",
			target:     cloudv1.AdminNodes,
			desiredVer: "1.24",
			curVer:     "1.26",
			wantRet:    false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if gotRet := ExpectToBeUpgraded(tt.target, tt.desiredVer, tt.curVer); gotRet != tt.wantRet {
				t.Errorf("expectToBeUpgraded() = %v, want %v", gotRet, tt.wantRet)
			}
		})
	}
}

func getTestComponentSpec(version string) opv1alpha1.ComponentSpec {
	return opv1alpha1.ComponentSpec{
		Annotations: map[string]string{
			RestartTiDBAnnotation: version,
		},
	}
}

func Test_mutateTCForRestarting(t *testing.T) {
	tests := []struct {
		name        string
		tc          *opv1alpha1.TidbCluster
		version     string
		wantChanged bool
	}{
		{
			name: "the annotation is not set",
			tc: &opv1alpha1.TidbCluster{
				Spec: opv1alpha1.TidbClusterSpec{
					PD:      &opv1alpha1.PDSpec{},
					TiKV:    &opv1alpha1.TiKVSpec{},
					TiDB:    &opv1alpha1.TiDBSpec{},
					TiFlash: &opv1alpha1.TiFlashSpec{},
				},
			},
			version:     "1.24",
			wantChanged: true,
		},
		{
			name: "the annotation is already set",
			tc: &opv1alpha1.TidbCluster{
				Spec: opv1alpha1.TidbClusterSpec{
					PD: &opv1alpha1.PDSpec{
						ComponentSpec: getTestComponentSpec("1.24"),
					},
					TiKV: &opv1alpha1.TiKVSpec{
						ComponentSpec: getTestComponentSpec("1.24"),
					},
					TiDB: &opv1alpha1.TiDBSpec{
						ComponentSpec: getTestComponentSpec("1.24"),
					},
					TiFlash: &opv1alpha1.TiFlashSpec{
						ComponentSpec: getTestComponentSpec("1.24"),
					},
				},
			},
			version:     "1.24",
			wantChanged: false,
		},
		{
			name: "the annotation value is different from the desired version",
			tc: &opv1alpha1.TidbCluster{
				Spec: opv1alpha1.TidbClusterSpec{
					PD: &opv1alpha1.PDSpec{
						ComponentSpec: getTestComponentSpec("1.24"),
					},
					TiKV: &opv1alpha1.TiKVSpec{
						ComponentSpec: getTestComponentSpec("1.24"),
					},
					TiDB: &opv1alpha1.TiDBSpec{
						ComponentSpec: getTestComponentSpec("1.24"),
					},
					TiFlash: &opv1alpha1.TiFlashSpec{
						ComponentSpec: getTestComponentSpec("1.24"),
					},
				},
			},
			version:     "1.25",
			wantChanged: true,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if gotChanged := MutateTCForRestarting(tt.tc, tt.version); gotChanged != tt.wantChanged {
				t.Errorf("MutateTCForRestarting() = %v, want %v", gotChanged, tt.wantChanged)
			}
		})
	}
}
