package ack

import (
	"testing"

	ossv1alpha1 "github.com/crossplane-contrib/provider-upjet-alibabacloud/apis/oss/v1alpha1"
	"github.com/stretchr/testify/assert"
	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	"k8s.io/utils/ptr"
)

func TestMakeLifecycleRules(t *testing.T) {
	tests := []struct {
		name     string
		rulesDef []v1alpha1.BucketLifecycleRule
		expected []ossv1alpha1.LifecycleRuleParameters
	}{
		{
			name:     "empty rules definition returns empty slice",
			rulesDef: []v1alpha1.BucketLifecycleRule{},
			expected: []ossv1alpha1.LifecycleRuleParameters{},
		},
		{
			name: "rule with prefix filter",
			rulesDef: []v1alpha1.BucketLifecycleRule{
				{
					Id:             "test-rule-2",
					Enabled:        true,
					PrefixFilter:   "test-prefix/",
					ExpirationDays: 30,
				},
			},
			expected: []ossv1alpha1.LifecycleRuleParameters{
				{
					ID:      ptr.To("test-rule-2"),
					Enabled: ptr.To(true),
					Prefix:  ptr.To("test-prefix/"),
					Expiration: []ossv1alpha1.ExpirationParameters{
						{Days: float64Ptr(30)},
					},
				},
			},
		},
		{
			name: "rule with tags filter",
			rulesDef: []v1alpha1.BucketLifecycleRule{
				{
					Id:      "test-rule-3",
					Enabled: true,
					TagsFilter: []v1alpha1.BucketTagFilter{
						{Key: "environment", Value: "production"},
						{Key: "team", Value: "backend"},
					},
					ExpirationDays: 20,
				},
			},
			expected: []ossv1alpha1.LifecycleRuleParameters{
				{
					ID:      ptr.To("test-rule-3"),
					Enabled: ptr.To(true),
					Tags: map[string]*string{
						"environment": ptr.To("production"),
						"team":        ptr.To("backend"),
					},
					Expiration: []ossv1alpha1.ExpirationParameters{
						{Days: float64Ptr(20)},
					},
				},
			},
		},
		{
			name: "rule with incomplete upload expiration days",
			rulesDef: []v1alpha1.BucketLifecycleRule{
				{
					Id:                             "test-rule-5",
					Enabled:                        true,
					IncompleteUploadExpirationDays: 7,
				},
			},
			expected: []ossv1alpha1.LifecycleRuleParameters{
				{
					ID:      ptr.To("test-rule-5"),
					Enabled: ptr.To(true),
					AbortMultipartUpload: []ossv1alpha1.AbortMultipartUploadParameters{
						{Days: float64Ptr(7)},
					},
				},
			},
		},
		{
			name: "rule with all filter",
			rulesDef: []v1alpha1.BucketLifecycleRule{
				{
					Id:             "test-rule-6",
					Enabled:        true,
					PrefixFilter:   "backup/",
					TagsFilter:     []v1alpha1.BucketTagFilter{{Key: "type", Value: "backup"}},
					ExpirationDays: 90,
				},
			},
			expected: []ossv1alpha1.LifecycleRuleParameters{
				{
					ID:      ptr.To("test-rule-6"),
					Enabled: ptr.To(true),
					Prefix:  ptr.To("backup/"),
					Tags: map[string]*string{
						"type": ptr.To("backup"),
					},
					Expiration: []ossv1alpha1.ExpirationParameters{
						{Days: float64Ptr(90.0)},
					},
				},
			},
		},
		{
			name: "multiple rules",
			rulesDef: []v1alpha1.BucketLifecycleRule{
				{
					Id:             "rule-1",
					Enabled:        true,
					PrefixFilter:   "logs/",
					ExpirationDays: 30,
				},
				{
					Id:                             "rule-2",
					Enabled:                        false,
					IncompleteUploadExpirationDays: 1,
				},
			},
			expected: []ossv1alpha1.LifecycleRuleParameters{
				{
					ID:      ptr.To("rule-1"),
					Enabled: ptr.To(true),
					Prefix:  ptr.To("logs/"),
					Expiration: []ossv1alpha1.ExpirationParameters{
						{Days: float64Ptr(30)},
					},
				},
				{
					ID:      ptr.To("rule-2"),
					Enabled: ptr.To(false),
					AbortMultipartUpload: []ossv1alpha1.AbortMultipartUploadParameters{
						{Days: float64Ptr(1)},
					},
				},
			},
		},
		{
			name: "same filter rules are merged into one OSS lifecycle rule",
			rulesDef: []v1alpha1.BucketLifecycleRule{
				{
					Id:             "expire-full-bucket",
					Enabled:        true,
					ExpirationDays: 1,
				},
				{
					Id:                             "abort-multipart",
					Enabled:                        true,
					IncompleteUploadExpirationDays: 1,
				},
			},
			expected: []ossv1alpha1.LifecycleRuleParameters{
				{
					ID:      ptr.To("expire-full-bucket"),
					Enabled: ptr.To(true),
					Expiration: []ossv1alpha1.ExpirationParameters{
						{Days: float64Ptr(1)},
					},
					AbortMultipartUpload: []ossv1alpha1.AbortMultipartUploadParameters{
						{Days: float64Ptr(1)},
					},
				},
			},
		},
		{
			name: "same filter rules with mixed enabled states are not merged",
			rulesDef: []v1alpha1.BucketLifecycleRule{
				{
					Id:             "expire-full-bucket",
					Enabled:        true,
					ExpirationDays: 1,
				},
				{
					Id:                             "abort-multipart",
					Enabled:                        false,
					IncompleteUploadExpirationDays: 1,
				},
			},
			expected: []ossv1alpha1.LifecycleRuleParameters{
				{
					ID:      ptr.To("expire-full-bucket"),
					Enabled: ptr.To(true),
					Expiration: []ossv1alpha1.ExpirationParameters{
						{Days: float64Ptr(1)},
					},
				},
				{
					ID:      ptr.To("abort-multipart"),
					Enabled: ptr.To(false),
					AbortMultipartUpload: []ossv1alpha1.AbortMultipartUploadParameters{
						{Days: float64Ptr(1)},
					},
				},
			},
		},
		{
			name: "same filter rules with duplicate actions are not merged",
			rulesDef: []v1alpha1.BucketLifecycleRule{
				{
					Id:             "expire-in-one-day",
					Enabled:        true,
					ExpirationDays: 1,
				},
				{
					Id:             "expire-in-seven-days",
					Enabled:        true,
					ExpirationDays: 7,
				},
			},
			expected: []ossv1alpha1.LifecycleRuleParameters{
				{
					ID:      ptr.To("expire-in-one-day"),
					Enabled: ptr.To(true),
					Expiration: []ossv1alpha1.ExpirationParameters{
						{Days: float64Ptr(1)},
					},
				},
				{
					ID:      ptr.To("expire-in-seven-days"),
					Enabled: ptr.To(true),
					Expiration: []ossv1alpha1.ExpirationParameters{
						{Days: float64Ptr(7)},
					},
				},
			},
		},
		{
			name: "same filter conflict prevents later complementary merge",
			rulesDef: []v1alpha1.BucketLifecycleRule{
				{
					Id:             "expire-in-one-day",
					Enabled:        true,
					ExpirationDays: 1,
				},
				{
					Id:             "expire-in-seven-days",
					Enabled:        true,
					ExpirationDays: 7,
				},
				{
					Id:                             "abort-multipart",
					Enabled:                        true,
					IncompleteUploadExpirationDays: 1,
				},
			},
			expected: []ossv1alpha1.LifecycleRuleParameters{
				{
					ID:      ptr.To("expire-in-one-day"),
					Enabled: ptr.To(true),
					Expiration: []ossv1alpha1.ExpirationParameters{
						{Days: float64Ptr(1)},
					},
				},
				{
					ID:      ptr.To("expire-in-seven-days"),
					Enabled: ptr.To(true),
					Expiration: []ossv1alpha1.ExpirationParameters{
						{Days: float64Ptr(7)},
					},
				},
				{
					ID:      ptr.To("abort-multipart"),
					Enabled: ptr.To(true),
					AbortMultipartUpload: []ossv1alpha1.AbortMultipartUploadParameters{
						{Days: float64Ptr(1)},
					},
				},
			},
		},
		{
			name: "tag filter key and value delimiters do not collide",
			rulesDef: []v1alpha1.BucketLifecycleRule{
				{
					Id:      "expire-tag-a",
					Enabled: true,
					TagsFilter: []v1alpha1.BucketTagFilter{
						{Key: "env=prod", Value: "team"},
					},
					ExpirationDays: 1,
				},
				{
					Id:      "abort-tag-b",
					Enabled: true,
					TagsFilter: []v1alpha1.BucketTagFilter{
						{Key: "env", Value: "prod=team"},
					},
					IncompleteUploadExpirationDays: 1,
				},
			},
			expected: []ossv1alpha1.LifecycleRuleParameters{
				{
					ID:      ptr.To("expire-tag-a"),
					Enabled: ptr.To(true),
					Tags: map[string]*string{
						"env=prod": ptr.To("team"),
					},
					Expiration: []ossv1alpha1.ExpirationParameters{
						{Days: float64Ptr(1)},
					},
				},
				{
					ID:      ptr.To("abort-tag-b"),
					Enabled: ptr.To(true),
					Tags: map[string]*string{
						"env": ptr.To("prod=team"),
					},
					AbortMultipartUpload: []ossv1alpha1.AbortMultipartUploadParameters{
						{Days: float64Ptr(1)},
					},
				},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := makeLifecycleRules(tt.rulesDef)

			assert.Equal(t, len(tt.expected), len(result), "Expected %d rules, got %d", len(tt.expected), len(result))

			for i, expectedRule := range tt.expected {
				actualRule := result[i]

				// Check basic fields
				assert.Equal(t, expectedRule.ID, actualRule.ID, "Rule %d ID mismatch", i)
				assert.Equal(t, expectedRule.Enabled, actualRule.Enabled, "Rule %d Enabled mismatch", i)
				assert.Equal(t, expectedRule.Prefix, actualRule.Prefix, "Rule %d Prefix mismatch", i)

				// Check tags
				if expectedRule.Tags == nil {
					assert.Nil(t, actualRule.Tags, "Rule %d Tags should be nil", i)
				} else {
					assert.Equal(t, expectedRule.Tags, actualRule.Tags, "Rule %d Tags mismatch", i)
				}

				// Check expiration
				if expectedRule.Expiration == nil {
					assert.Nil(t, actualRule.Expiration, "Rule %d Expiration should be nil", i)
				} else {
					assert.Equal(t, expectedRule.Expiration, actualRule.Expiration, "Rule %d Expiration mismatch", i)
				}

				// Check abort multipart upload
				if expectedRule.AbortMultipartUpload == nil {
					assert.Nil(t, actualRule.AbortMultipartUpload, "Rule %d AbortMultipartUpload should be nil", i)
				} else {
					assert.Equal(t, expectedRule.AbortMultipartUpload, actualRule.AbortMultipartUpload, "Rule %d AbortMultipartUpload mismatch", i)
				}
			}
		})
	}
}

func float64Ptr(f float64) *float64 {
	return &f
}
