package aks

import (
	"reflect"
	"testing"

	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	storagev1beta1 "github.com/upbound/provider-azure/apis/storage/v1beta1"
	"k8s.io/utils/ptr"
)

func TestDoCollectLifecycleRules(t *testing.T) {
	tests := []struct {
		name    string
		buckets []*v1alpha1.Bucket
		want    []storagev1beta1.RuleParameters
	}{
		{
			name: "filters invalid rules and buckets",
			buckets: []*v1alpha1.Bucket{
				{
					Status: v1alpha1.BucketStatus{
						Bucket: &v1alpha1.Reference{Name: "container1"},
					},
					Spec: v1alpha1.BucketSpec{
						LifecycleRules: []v1alpha1.BucketLifecycleRule{
							{Id: "r1", Enabled: true, ExpirationDays: 7},
							{Id: "r2", ExpirationDays: 0},
							{Id: "r3", ExpirationDays: 30, IncompleteUploadExpirationDays: 1},
						},
					},
				},
				{
					Status: v1alpha1.BucketStatus{
						Bucket: nil,
					},
					Spec: v1alpha1.BucketSpec{
						LifecycleRules: []v1alpha1.BucketLifecycleRule{
							{Id: "r4", ExpirationDays: 10},
						},
					},
				},
				{
					Status: v1alpha1.BucketStatus{
						Bucket: &v1alpha1.Reference{Name: ""},
					},
					Spec: v1alpha1.BucketSpec{
						LifecycleRules: []v1alpha1.BucketLifecycleRule{
							{Id: "r5", ExpirationDays: 10},
						},
					},
				},
				{
					Status: v1alpha1.BucketStatus{
						Bucket: &v1alpha1.Reference{Name: "container2"},
					},
					Spec: v1alpha1.BucketSpec{
						LifecycleRules: []v1alpha1.BucketLifecycleRule{
							{
								Id:             "r6",
								Enabled:        false,
								PrefixFilter:   "logs",
								ExpirationDays: 30,
								TagsFilter: []v1alpha1.BucketTagFilter{
									{Key: "env", Value: "prod"},
									{Key: "team", Value: "infra"},
								},
							},
						},
					},
				},
			},
			want: []storagev1beta1.RuleParameters{
				{
					Name:    ptr.To(lifecycleRuleName("container1", "r1")),
					Enabled: ptr.To(true),
					Filters: []storagev1beta1.FiltersParameters{
						{
							PrefixMatch: []*string{ptr.To("container1/")},
							BlobTypes:   []*string{ptr.To("blockBlob")},
						},
					},
					Actions: []storagev1beta1.ActionsParameters{
						{
							BaseBlob: []storagev1beta1.BaseBlobParameters{
								{DeleteAfterDaysSinceModificationGreaterThan: ptr.To(float64(7))},
							},
						},
					},
				},
				{
					Name:    ptr.To(lifecycleRuleName("container2", "r6")),
					Enabled: ptr.To(false),
					Filters: []storagev1beta1.FiltersParameters{
						{
							PrefixMatch: []*string{ptr.To("container2/logs/")},
							BlobTypes:   []*string{ptr.To("blockBlob")},
							MatchBlobIndexTag: []storagev1beta1.MatchBlobIndexTagParameters{
								{Name: ptr.To("env"), Operation: ptr.To("=="), Value: ptr.To("prod")},
								{Name: ptr.To("team"), Operation: ptr.To("=="), Value: ptr.To("infra")},
							},
						},
					},
					Actions: []storagev1beta1.ActionsParameters{
						{
							BaseBlob: []storagev1beta1.BaseBlobParameters{
								{DeleteAfterDaysSinceModificationGreaterThan: ptr.To(float64(30))},
							},
						},
					},
				},
			},
		},
		{
			name:    "no buckets",
			buckets: nil,
			want:    nil,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := doCollectLifecycleRules(tt.buckets)
			if !reflect.DeepEqual(got, tt.want) {
				t.Fatalf("doCollectLifecycleRules() = %#v, want %#v", got, tt.want)
			}
		})
	}
}

func TestMakeLifecycleRule(t *testing.T) {
	tests := []struct {
		name          string
		containerName string
		rule          v1alpha1.BucketLifecycleRule
		want          storagev1beta1.RuleParameters
	}{
		{
			name:          "no prefix or tags",
			containerName: "container1",
			rule: v1alpha1.BucketLifecycleRule{
				Id:             "r1",
				Enabled:        true,
				ExpirationDays: 7,
			},
			want: storagev1beta1.RuleParameters{
				Name:    ptr.To(lifecycleRuleName("container1", "r1")),
				Enabled: ptr.To(true),
				Filters: []storagev1beta1.FiltersParameters{
					{
						PrefixMatch: []*string{ptr.To("container1/")},
						BlobTypes:   []*string{ptr.To("blockBlob")},
					},
				},
				Actions: []storagev1beta1.ActionsParameters{
					{
						BaseBlob: []storagev1beta1.BaseBlobParameters{
							{DeleteAfterDaysSinceModificationGreaterThan: ptr.To(float64(7))},
						},
					},
				},
			},
		},
		{
			name:          "prefix and tags",
			containerName: "container2",
			rule: v1alpha1.BucketLifecycleRule{
				Id:             "r2",
				Enabled:        false,
				PrefixFilter:   "logs/",
				ExpirationDays: 30,
				TagsFilter: []v1alpha1.BucketTagFilter{
					{Key: "env", Value: "prod"},
					{Key: "team", Value: "infra"},
				},
			},
			want: storagev1beta1.RuleParameters{
				Name:    ptr.To(lifecycleRuleName("container2", "r2")),
				Enabled: ptr.To(false),
				Filters: []storagev1beta1.FiltersParameters{
					{
						PrefixMatch: []*string{ptr.To("container2/logs/")},
						BlobTypes:   []*string{ptr.To("blockBlob")},
						MatchBlobIndexTag: []storagev1beta1.MatchBlobIndexTagParameters{
							{Name: ptr.To("env"), Operation: ptr.To("=="), Value: ptr.To("prod")},
							{Name: ptr.To("team"), Operation: ptr.To("=="), Value: ptr.To("infra")},
						},
					},
				},
				Actions: []storagev1beta1.ActionsParameters{
					{
						BaseBlob: []storagev1beta1.BaseBlobParameters{
							{DeleteAfterDaysSinceModificationGreaterThan: ptr.To(float64(30))},
						},
					},
				},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := makeLifecycleRule(tt.containerName, tt.rule)
			if !reflect.DeepEqual(got, tt.want) {
				t.Fatalf("makeLifecycleRule() = %#v, want %#v", got, tt.want)
			}
		})
	}
}
