package controllers

import (
	"reflect"
	"testing"

	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/controller-runtime/pkg/event"
)

func TestAnnotationPredicate_Update(t *testing.T) {
	tests := []struct {
		name string
		e    event.UpdateEvent
		want bool
	}{
		{
			name: "no annotation change",
			e: event.UpdateEvent{
				ObjectOld: &v1alpha1.APPBox{
					ObjectMeta: metav1.ObjectMeta{
						Annotations: map[string]string{
							"test-annotation": "value",
						},
					},
				},
				ObjectNew: &v1alpha1.APPBox{
					ObjectMeta: metav1.ObjectMeta{
						Annotations: map[string]string{
							"test-annotation": "value",
						},
					},
				},
			},
			want: false,
		},
		{
			name: "annotation changed",
			e: event.UpdateEvent{
				ObjectOld: &v1alpha1.APPBox{
					ObjectMeta: metav1.ObjectMeta{
						Annotations: map[string]string{
							"test-annotation": "old-value",
						},
					},
				},
				ObjectNew: &v1alpha1.APPBox{
					ObjectMeta: metav1.ObjectMeta{
						Annotations: map[string]string{
							"test-annotation": "new-value",
						},
					},
				},
			},
			want: true,
		},
		{
			name: "with new gc annotation",
			e: event.UpdateEvent{
				ObjectOld: &v1alpha1.APPBox{
					ObjectMeta: metav1.ObjectMeta{
						Annotations: map[string]string{
							"test-annotation": "old-value",
						},
					},
				},
				ObjectNew: &v1alpha1.APPBox{
					ObjectMeta: metav1.ObjectMeta{
						Annotations: map[string]string{
							"test-annotation":                             "old-value",
							v1alpha1.SkipGCAnnotationKey:                  v1alpha1.SkipGCAnnotationVal,
							v1alpha1.AnnotationKeyIdelStartTime:           "2021-01-01T00:00:00Z",
							v1alpha1.AnnotationKeyReadyForDeleteStartTime: "2021-01-01T00:00:00Z",
						},
					},
				},
			},
			want: false,
		},
		{
			name: "old gc annotation changed",
			e: event.UpdateEvent{
				ObjectOld: &v1alpha1.APPBox{
					ObjectMeta: metav1.ObjectMeta{
						Annotations: map[string]string{
							"test-annotation":                             "old-value",
							v1alpha1.SkipGCAnnotationKey:                  v1alpha1.SkipGCAnnotationVal,
							v1alpha1.AnnotationKeyIdelStartTime:           "2021-01-01T00:00:00Z",
							v1alpha1.AnnotationKeyReadyForDeleteStartTime: "2021-01-01T00:00:00Z",
						},
					},
				},
				ObjectNew: &v1alpha1.APPBox{
					ObjectMeta: metav1.ObjectMeta{
						Annotations: map[string]string{
							"test-annotation":                             "old-value",
							v1alpha1.SkipGCAnnotationKey:                  "false",
							v1alpha1.AnnotationKeyIdelStartTime:           "",
							v1alpha1.AnnotationKeyReadyForDeleteStartTime: "",
						},
					},
				},
			},
			want: false,
		},
		{
			name: "other and gc annotation changed",
			e: event.UpdateEvent{
				ObjectOld: &v1alpha1.APPBox{
					ObjectMeta: metav1.ObjectMeta{
						Annotations: map[string]string{
							"test-annotation":                             "old-value",
							v1alpha1.SkipGCAnnotationKey:                  v1alpha1.SkipGCAnnotationVal,
							v1alpha1.AnnotationKeyIdelStartTime:           "2021-01-01T00:00:00Z",
							v1alpha1.AnnotationKeyReadyForDeleteStartTime: "2021-01-01T00:00:00Z",
						},
					},
				},
				ObjectNew: &v1alpha1.APPBox{
					ObjectMeta: metav1.ObjectMeta{
						Annotations: map[string]string{
							"test-annotation":                             "new-value",
							v1alpha1.SkipGCAnnotationKey:                  "false",
							v1alpha1.AnnotationKeyIdelStartTime:           "",
							v1alpha1.AnnotationKeyReadyForDeleteStartTime: "",
						},
					},
				},
			},
			want: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			p := AnnotationChangedPredicate{}
			if got := p.Update(tt.e); got != tt.want {
				t.Errorf("AnnotationPredicate.Update() = %v, want %v", got, tt.want)
			}
		})
	}
}

func Test_deepCopy(t *testing.T) {
	tests := []struct {
		name string
		m    map[string]string
		want map[string]string
	}{
		{
			name: "empty map",
			m:    map[string]string{},
			want: map[string]string{},
		},
		{
			name: "non-empty map",
			m:    map[string]string{"key": "value", "key2": "value2"},
			want: map[string]string{"key": "value", "key2": "value2"},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := deepCopy(tt.m); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("deepCopy() = %v, want %v", got, tt.want)
			}
		})
	}
}
