package cluster

import (
	"fmt"
	"testing"

	. "github.com/onsi/gomega"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"

	"github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
)

func TestWhenPhaseIn(t *testing.T) {
	cases := map[string]struct {
		filter  whenPhaseIn
		cluster *cloudv1.Cluster
		allow   bool
	}{
		"AllowPhase": {
			filter: whenPhaseIn([]cloudv1.ClusterPhase{cloudv1.ClusterPhaseRunning}),
			cluster: &cloudv1.Cluster{
				Status: cloudv1.ClusterStatus{
					Phase: cloudv1.ClusterPhaseRunning,
				},
			},
			allow: true,
		},
		"DenyPhase": {
			filter: whenPhaseIn([]cloudv1.ClusterPhase{cloudv1.ClusterPhaseRunning}),
			cluster: &cloudv1.Cluster{
				Status: cloudv1.ClusterStatus{
					Phase: cloudv1.ClusterPhaseUpgrading,
				},
			},
			allow: false,
		},
	}
	for name, tc := range cases {
		t.Run(name, func(t *testing.T) {
			g := NewGomegaWithT(t)
			g.Expect(tc.filter.Allow(tc.cluster)).To(Equal(tc.allow))
		})
	}
}

func TestMutateTidbCluster(t *testing.T) {
	cases := map[string]struct {
		tc       *v1alpha1.TidbCluster
		mutateFn func(*v1alpha1.TidbCluster) error
		mutated  bool
		err      bool
	}{
		"Update": {
			tc: &v1alpha1.TidbCluster{
				ObjectMeta: v1.ObjectMeta{Name: "test"},
				Spec: v1alpha1.TidbClusterSpec{
					Version: "v5.0.0",
				},
			},
			mutateFn: func(tc *v1alpha1.TidbCluster) error {
				tc.Spec.Version = "v5.0.1"
				return nil
			},
			mutated: true,
			err:     false,
		},
		"NoUpdate": {
			tc: &v1alpha1.TidbCluster{
				ObjectMeta: v1.ObjectMeta{Name: "test"},
				Spec: v1alpha1.TidbClusterSpec{
					Version: "v5.0.1",
				},
			},
			mutateFn: func(tc *v1alpha1.TidbCluster) error {
				tc.Spec.Version = "v5.0.1"
				return nil
			},
			mutated: false,
			err:     false,
		},
		"MutateError": {
			tc: &v1alpha1.TidbCluster{
				ObjectMeta: v1.ObjectMeta{Name: "test"},
				Spec: v1alpha1.TidbClusterSpec{
					Version: "v5.0.1",
				},
			},
			mutateFn: func(tc *v1alpha1.TidbCluster) error {
				return fmt.Errorf("error mutating")
			},
			mutated: false,
			err:     true,
		},
	}
	for name, tc := range cases {
		t.Run(name, func(t *testing.T) {
			g := NewGomegaWithT(t)
			r := newFakeReconcileContext(
				&cloudv1.Cluster{ObjectMeta: v1.ObjectMeta{Name: "test", Namespace: defaultNamespace}},
				newFakeReconciler([]runtime.Object{tc.tc}, nil))
			r.tc = tc.tc
			mutated, err := r.mutateTidbCluster(tc.mutateFn)
			g.Expect(mutated).To(Equal(tc.mutated))
			if tc.err {
				g.Expect(err).NotTo(Succeed())
			} else {
				g.Expect(err).To(Succeed())
			}
		})
	}
}
