package common

import (
	"context"
	"testing"

	vmv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1"
	"github.com/go-logr/logr/testr"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	observabilitypingcapcomv1 "github.com/tidbcloud/observability/api/regionalserver/resourceworker/v1"
	"github.com/tidbcloud/observability/pkg/common/constants"
	"github.com/tidbcloud/observability/pkg/resourceworker/controllers/serverless/task"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"
)

func TestNewVMRule(t *testing.T) {
	ctx := &task.Context{
		Cluster: &observabilitypingcapcomv1.Cluster{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "test-cluster",
				Namespace: "test-namespace",
			},
		},
		Logger: testr.New(t),
	}

	vmr := NewVMRule(ctx)
	assert.NotNil(t, vmr)
	assert.Equal(t, ctx, vmr.Context)
}

func TestVMRule_Name(t *testing.T) {
	ctx := &task.Context{
		Cluster: &observabilitypingcapcomv1.Cluster{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "test-cluster",
				Namespace: "test-namespace",
			},
		},
		Logger: testr.New(t),
	}

	vmr := NewVMRule(ctx)
	assert.Equal(t, "VMRule", vmr.Name())
}

func TestVMRule_Create_NoTemplateID(t *testing.T) {
	scheme := runtime.NewScheme()
	_ = vmv1beta1.AddToScheme(scheme)
	_ = observabilitypingcapcomv1.AddToScheme(scheme)

	ctx := &task.Context{
		Cluster: &observabilitypingcapcomv1.Cluster{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "test-cluster",
				Namespace: "test-namespace",
				Labels:    map[string]string{},
			},
		},
		Logger: testr.New(t),
		Remote: fake.NewClientBuilder().WithScheme(scheme).Build(),
	}

	vmr := NewVMRule(ctx)
	result := vmr.Create(context.Background())

	assert.True(t, result.IsDoneState())
	assert.Nil(t, result.Error())
}

func TestVMRule_Create_TemplateNotFound(t *testing.T) {
	scheme := runtime.NewScheme()
	_ = vmv1beta1.AddToScheme(scheme)
	_ = observabilitypingcapcomv1.AddToScheme(scheme)

	ctx := &task.Context{
		Cluster: &observabilitypingcapcomv1.Cluster{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "test-cluster",
				Namespace: "test-namespace",
				Labels: map[string]string{
					constants.LabelTemplateID: "template-123",
				},
			},
		},
		Logger: testr.New(t),
		Remote: fake.NewClientBuilder().WithScheme(scheme).Build(),
	}

	vmr := NewVMRule(ctx)
	result := vmr.Create(context.Background())

	assert.True(t, result.IsDoneState())
	assert.Nil(t, result.Error())
}

func TestVMRule_Create_Success(t *testing.T) {
	scheme := runtime.NewScheme()
	_ = vmv1beta1.AddToScheme(scheme)
	_ = observabilitypingcapcomv1.AddToScheme(scheme)

	templateRule := &vmv1beta1.VMRule{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "template-123",
			Namespace: constants.AlertRuleTemplateNamespace,
		},
		Spec: vmv1beta1.VMRuleSpec{
			Groups: []vmv1beta1.RuleGroup{
				{
					Name:     "test-group",
					Interval: "30s",
					Rules: []vmv1beta1.Rule{
						{
							Alert: "TestAlert",
							Expr:  "up == 0",
							For:   "5m",
							Labels: map[string]string{
								constants.RuleLabelID:         "rule-1",
								constants.RuleLabelStatus:     string(constants.RULE_ACTIVE),
								constants.RuleLabelVisibility: "internal",
							},
							Annotations: map[string]string{
								constants.RuleAnnotationsMessage: "Test message",
							},
						},
					},
				},
			},
		},
	}

	ctx := &task.Context{
		Cluster: &observabilitypingcapcomv1.Cluster{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "test-cluster",
				Namespace: "test-namespace",
				Labels: map[string]string{
					constants.LabelTemplateID:    "template-123",
					constants.LabelTenantID:      "tenant-1",
					constants.LabelProjectID:     "project-1",
					constants.LabelApplicationID: "app-1",
					constants.LabelBizType:       "test-biz",
					constants.LabelVendor:        "aws",
					constants.LabelRegion:        "us-west-2",
				},
			},
			Spec: observabilitypingcapcomv1.ClusterSpec{
				VictoriaAccount: observabilitypingcapcomv1.VictoriaAccount{
					AccountID: 123,
					ProjectID: 456,
				},
			},
		},
		Logger: testr.New(t),
		Remote: fake.NewClientBuilder().WithScheme(scheme).WithObjects(templateRule).Build(),
	}

	vmr := NewVMRule(ctx)
	result := vmr.Create(context.Background())

	assert.True(t, result.IsDoneState())
	assert.Nil(t, result.Error())

	// Verify the VMRule was created
	createdRule := &vmv1beta1.VMRule{}
	err := ctx.Remote.Get(context.Background(), types.NamespacedName{
		Name:      "test-cluster",
		Namespace: "test-namespace",
	}, createdRule)
	require.NoError(t, err)
	assert.Equal(t, "true", createdRule.Labels[constants.LabelMultiTenancyRule])
	assert.Equal(t, "tenant-1", createdRule.Labels[constants.LabelTenantID])
	assert.Equal(t, "project-1", createdRule.Labels[constants.LabelProjectID])
	assert.Equal(t, "app-1", createdRule.Labels[constants.LabelApplicationID])
	assert.Equal(t, "test-biz", createdRule.Labels[constants.LabelBizType])
}

func TestVMRule_Create_WithMuteAlert(t *testing.T) {
	scheme := runtime.NewScheme()
	_ = vmv1beta1.AddToScheme(scheme)
	_ = observabilitypingcapcomv1.AddToScheme(scheme)

	templateRule := &vmv1beta1.VMRule{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "template-123",
			Namespace: constants.AlertRuleTemplateNamespace,
		},
		Spec: vmv1beta1.VMRuleSpec{
			Groups: []vmv1beta1.RuleGroup{
				{
					Name:  "test-group",
					Rules: []vmv1beta1.Rule{},
				},
			},
		},
	}

	ctx := &task.Context{
		Cluster: &observabilitypingcapcomv1.Cluster{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "test-cluster",
				Namespace: "test-namespace",
				Labels: map[string]string{
					constants.LabelTemplateID:    "template-123",
					constants.LabelTenantID:      "tenant-1",
					constants.LabelProjectID:     "project-1",
					constants.LabelApplicationID: "app-1",
					constants.LabelBizType:       "test-biz",
					constants.LabelVendor:        "aws",
					constants.LabelRegion:        "us-west-2",
				},
			},
			Spec: observabilitypingcapcomv1.ClusterSpec{
				MuteAlert: true,
				VictoriaAccount: observabilitypingcapcomv1.VictoriaAccount{
					AccountID: 123,
					ProjectID: 456,
				},
			},
		},
		Logger: testr.New(t),
		Remote: fake.NewClientBuilder().WithScheme(scheme).WithObjects(templateRule).Build(),
	}

	vmr := NewVMRule(ctx)
	result := vmr.Create(context.Background())

	assert.True(t, result.IsDoneState())
	assert.Nil(t, result.Error())

	// Verify the VMRule is NOT created (or deleted if it existed)
	createdRule := &vmv1beta1.VMRule{}
	err := ctx.Remote.Get(context.Background(), types.NamespacedName{
		Name:      "test-cluster",
		Namespace: "test-namespace",
	}, createdRule)

	// We expect NotFound error because Create should call Delete when MuteAlert is true
	assert.True(t, apierrors.IsNotFound(err), "VMRule should be deleted when MuteAlert is true")
}

func TestVMRule_Create_WithPausingStatus(t *testing.T) {
	scheme := runtime.NewScheme()
	_ = vmv1beta1.AddToScheme(scheme)
	_ = observabilitypingcapcomv1.AddToScheme(scheme)

	templateRule := &vmv1beta1.VMRule{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "template-123",
			Namespace: constants.AlertRuleTemplateNamespace,
		},
		Spec: vmv1beta1.VMRuleSpec{
			Groups: []vmv1beta1.RuleGroup{
				{
					Name:  "test-group",
					Rules: []vmv1beta1.Rule{},
				},
			},
		},
	}

	ctx := &task.Context{
		Cluster: &observabilitypingcapcomv1.Cluster{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "test-cluster",
				Namespace: "test-namespace",
				Labels: map[string]string{
					constants.LabelTemplateID:    "template-123",
					constants.LabelTenantID:      "tenant-1",
					constants.LabelProjectID:     "project-1",
					constants.LabelApplicationID: "app-1",
					constants.LabelBizType:       "test-biz",
					constants.LabelVendor:        "aws",
					constants.LabelRegion:        "us-west-2",
				},
			},
			Spec: observabilitypingcapcomv1.ClusterSpec{
				VictoriaAccount: observabilitypingcapcomv1.VictoriaAccount{
					AccountID: 123,
					ProjectID: 456,
				},
			},
			Status: observabilitypingcapcomv1.ClusterStatus{
				Phase: constants.PAUSING,
			},
		},
		Logger: testr.New(t),
		Remote: fake.NewClientBuilder().WithScheme(scheme).WithObjects(templateRule).Build(),
	}

	vmr := NewVMRule(ctx)
	result := vmr.Create(context.Background())

	assert.True(t, result.IsDoneState())
	assert.Nil(t, result.Error())

	// Verify the VMRule has the paused label
	createdRule := &vmv1beta1.VMRule{}
	err := ctx.Remote.Get(context.Background(), types.NamespacedName{
		Name:      "test-cluster",
		Namespace: "test-namespace",
	}, createdRule)
	require.NoError(t, err)
	assert.Equal(t, "true", createdRule.Labels[constants.LabelClusterPaused])
}

func TestVMRule_Delete_NotFound(t *testing.T) {
	scheme := runtime.NewScheme()
	_ = vmv1beta1.AddToScheme(scheme)
	_ = observabilitypingcapcomv1.AddToScheme(scheme)

	ctx := &task.Context{
		Cluster: &observabilitypingcapcomv1.Cluster{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "test-cluster",
				Namespace: "test-namespace",
			},
		},
		Logger: testr.New(t),
		Remote: fake.NewClientBuilder().WithScheme(scheme).Build(),
	}

	vmr := NewVMRule(ctx)
	result := vmr.Delete(context.Background())

	assert.True(t, result.IsDoneState())
	assert.Nil(t, result.Error())
}

func TestVMRule_Delete_Success(t *testing.T) {
	scheme := runtime.NewScheme()
	_ = vmv1beta1.AddToScheme(scheme)
	_ = observabilitypingcapcomv1.AddToScheme(scheme)

	existingRule := &vmv1beta1.VMRule{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "test-cluster",
			Namespace: "test-namespace",
		},
		Spec: vmv1beta1.VMRuleSpec{
			Groups: []vmv1beta1.RuleGroup{},
		},
	}

	ctx := &task.Context{
		Cluster: &observabilitypingcapcomv1.Cluster{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "test-cluster",
				Namespace: "test-namespace",
			},
		},
		Logger: testr.New(t),
		Remote: fake.NewClientBuilder().WithScheme(scheme).WithObjects(existingRule).Build(),
	}

	vmr := NewVMRule(ctx)
	result := vmr.Delete(context.Background())

	assert.Error(t, result.Error())

	// Verify the VMRule is being deleted
	deletedRule := &vmv1beta1.VMRule{}
	err := ctx.Remote.Get(context.Background(), types.NamespacedName{
		Name:      "test-cluster",
		Namespace: "test-namespace",
	}, deletedRule)
	assert.True(t, apierrors.IsNotFound(err))
}

func TestAlertRuleMerge(t *testing.T) {
	tests := []struct {
		name          string
		templateRules vmv1beta1.VMRuleSpec
		overlayRules  vmv1beta1.VMRuleSpec
		cluster       *observabilitypingcapcomv1.Cluster
		expectedLen   int
		validate      func(t *testing.T, result vmv1beta1.VMRuleSpec)
	}{
		{
			name: "merge with overlay rules - status modified",
			templateRules: vmv1beta1.VMRuleSpec{
				Groups: []vmv1beta1.RuleGroup{
					{
						Name:     "group1",
						Interval: "30s",
						Rules: []vmv1beta1.Rule{
							{
								Alert: "TestAlert",
								Expr:  "up == 0",
								For:   "5m",
								Labels: map[string]string{
									constants.RuleLabelID:         "rule-1",
									constants.RuleLabelStatus:     string(constants.RULE_ACTIVE),
									constants.RuleLabelVisibility: "internal",
								},
							},
						},
					},
				},
			},
			overlayRules: vmv1beta1.VMRuleSpec{
				Groups: []vmv1beta1.RuleGroup{
					{
						Name: "group1",
						Rules: []vmv1beta1.Rule{
							{
								Alert: "TestAlert",
								Expr:  "up == 0",
								Labels: map[string]string{
									constants.RuleLabelID:           "rule-1",
									constants.RuleLabelUserModified: "1", // Status modified
									constants.RuleLabelStatus:       string(constants.RULE_DISABLED),
								},
							},
						},
					},
				},
			},
			cluster: &observabilitypingcapcomv1.Cluster{
				ObjectMeta: metav1.ObjectMeta{
					Labels: map[string]string{
						constants.LabelTenantID:      "tenant-1",
						constants.LabelProjectID:     "project-1",
						constants.LabelApplicationID: "app-1",
						constants.LabelBizType:       "test-biz",
						constants.LabelVendor:        "aws",
						constants.LabelRegion:        "us-west-2",
					},
				},
				Spec: observabilitypingcapcomv1.ClusterSpec{
					VictoriaAccount: observabilitypingcapcomv1.VictoriaAccount{
						AccountID: 123,
						ProjectID: 456,
					},
				},
			},
			expectedLen: 0, // Rule is disabled, should be filtered out
			validate: func(t *testing.T, result vmv1beta1.VMRuleSpec) {
				assert.Equal(t, 1, len(result.Groups))
				assert.Equal(t, 0, len(result.Groups[0].Rules))
			},
		},
		{
			name: "merge with overlay rules - threshold modified",
			templateRules: vmv1beta1.VMRuleSpec{
				Groups: []vmv1beta1.RuleGroup{
					{
						Name:     "group1",
						Interval: "30s",
						Rules: []vmv1beta1.Rule{
							{
								Alert: "TestAlert",
								Expr:  "cpu_usage > 0.8",
								For:   "5m",
								Labels: map[string]string{
									constants.RuleLabelID:         "rule-1",
									constants.RuleLabelStatus:     string(constants.RULE_ACTIVE),
									constants.RuleLabelVisibility: "internal",
								},
							},
						},
					},
				},
			},
			overlayRules: vmv1beta1.VMRuleSpec{
				Groups: []vmv1beta1.RuleGroup{
					{
						Name: "group1",
						Rules: []vmv1beta1.Rule{
							{
								Alert: "TestAlert",
								Expr:  "cpu_usage > 0.9",
								Labels: map[string]string{
									constants.RuleLabelID:           "rule-1",
									constants.RuleLabelUserModified: "2", // Threshold modified
									constants.RuleLabelStatus:       string(constants.RULE_ACTIVE),
								},
							},
						},
					},
				},
			},
			cluster: &observabilitypingcapcomv1.Cluster{
				ObjectMeta: metav1.ObjectMeta{
					Labels: map[string]string{
						constants.LabelTenantID:      "tenant-1",
						constants.LabelProjectID:     "project-1",
						constants.LabelApplicationID: "app-1",
						constants.LabelBizType:       "test-biz",
						constants.LabelVendor:        "aws",
						constants.LabelRegion:        "us-west-2",
					},
				},
				Spec: observabilitypingcapcomv1.ClusterSpec{
					VictoriaAccount: observabilitypingcapcomv1.VictoriaAccount{
						AccountID: 123,
						ProjectID: 456,
					},
				},
			},
			expectedLen: 1,
			validate: func(t *testing.T, result vmv1beta1.VMRuleSpec) {
				assert.Equal(t, 1, len(result.Groups))
				assert.Equal(t, 1, len(result.Groups[0].Rules))
				assert.Contains(t, result.Groups[0].Rules[0].Expr, "0.9")
			},
		},
		{
			name: "merge with overlay rules - for duration modified",
			templateRules: vmv1beta1.VMRuleSpec{
				Groups: []vmv1beta1.RuleGroup{
					{
						Name:     "group1",
						Interval: "30s",
						Rules: []vmv1beta1.Rule{
							{
								Alert: "TestAlert",
								Expr:  "up == 0",
								For:   "5m",
								Labels: map[string]string{
									constants.RuleLabelID:         "rule-1",
									constants.RuleLabelStatus:     string(constants.RULE_ACTIVE),
									constants.RuleLabelVisibility: "internal",
								},
							},
						},
					},
				},
			},
			overlayRules: vmv1beta1.VMRuleSpec{
				Groups: []vmv1beta1.RuleGroup{
					{
						Name: "group1",
						Rules: []vmv1beta1.Rule{
							{
								Alert: "TestAlert",
								Expr:  "up == 0",
								For:   "10m",
								Labels: map[string]string{
									constants.RuleLabelID:           "rule-1",
									constants.RuleLabelUserModified: "4", // For modified
									constants.RuleLabelStatus:       string(constants.RULE_ACTIVE),
								},
							},
						},
					},
				},
			},
			cluster: &observabilitypingcapcomv1.Cluster{
				ObjectMeta: metav1.ObjectMeta{
					Labels: map[string]string{
						constants.LabelTenantID:      "tenant-1",
						constants.LabelProjectID:     "project-1",
						constants.LabelApplicationID: "app-1",
						constants.LabelBizType:       "test-biz",
						constants.LabelVendor:        "aws",
						constants.LabelRegion:        "us-west-2",
					},
				},
				Spec: observabilitypingcapcomv1.ClusterSpec{
					VictoriaAccount: observabilitypingcapcomv1.VictoriaAccount{
						AccountID: 123,
						ProjectID: 456,
					},
				},
			},
			expectedLen: 1,
			validate: func(t *testing.T, result vmv1beta1.VMRuleSpec) {
				assert.Equal(t, 1, len(result.Groups))
				assert.Equal(t, 1, len(result.Groups[0].Rules))
				assert.Equal(t, "10m", result.Groups[0].Rules[0].For)
			},
		},
		{
			name: "external rule with placeholder replacement",
			templateRules: vmv1beta1.VMRuleSpec{
				Groups: []vmv1beta1.RuleGroup{
					{
						Name:     "group1",
						Interval: "30s",
						Rules: []vmv1beta1.Rule{
							{
								Alert: "TestAlert-{severity}",
								Expr:  "cpu_usage > 0.8",
								For:   "5m",
								Labels: map[string]string{
									constants.RuleLabelID:            "rule-1",
									constants.RuleLabelStatus:        string(constants.RULE_ACTIVE),
									constants.RuleLabelVisibility:    "external",
									constants.RuleLabelSeverity:      "critical",
									constants.RuleLabelCanEdit:       "all",
									constants.RuleLabelOperator:      ">",
									constants.RuleLabelMonitortarget: "cpu",
								},
								Annotations: map[string]string{
									constants.RuleAnnotationsMessage:     "CPU usage is above {threshold}",
									constants.RuleAnnotationsDescription: "The threshold is {thresholdPercentage}%",
									constants.RuleAnnotationsSummary:     "Alert for {triggerInterval} minutes",
								},
							},
						},
					},
				},
			},
			overlayRules: vmv1beta1.VMRuleSpec{
				Groups: []vmv1beta1.RuleGroup{},
			},
			cluster: &observabilitypingcapcomv1.Cluster{
				ObjectMeta: metav1.ObjectMeta{
					Labels: map[string]string{
						constants.LabelTenantID:      "tenant-1",
						constants.LabelProjectID:     "project-1",
						constants.LabelApplicationID: "app-1",
						constants.LabelBizType:       "test-biz",
						constants.LabelVendor:        "aws",
						constants.LabelRegion:        "us-west-2",
					},
				},
				Spec: observabilitypingcapcomv1.ClusterSpec{
					VictoriaAccount: observabilitypingcapcomv1.VictoriaAccount{
						AccountID: 123,
						ProjectID: 456,
					},
				},
			},
			expectedLen: 1,
			validate: func(t *testing.T, result vmv1beta1.VMRuleSpec) {
				assert.Equal(t, 1, len(result.Groups))
				assert.Equal(t, 1, len(result.Groups[0].Rules))
				rule := result.Groups[0].Rules[0]

				// Check that placeholders are replaced
				assert.Contains(t, rule.Alert, "critical")
				assert.NotContains(t, rule.Alert, "{severity}")
				assert.Contains(t, rule.Annotations[constants.RuleAnnotationsMessage], "0.8")
				assert.NotContains(t, rule.Annotations[constants.RuleAnnotationsMessage], "{threshold}")

				// Check that internal labels are removed
				_, hasCanEdit := rule.Labels[constants.RuleLabelCanEdit]
				assert.False(t, hasCanEdit)
				_, hasOperator := rule.Labels[constants.RuleLabelOperator]
				assert.False(t, hasOperator)
				_, hasMonitorTarget := rule.Labels[constants.RuleLabelMonitortarget]
				assert.False(t, hasMonitorTarget)
				_, hasStatus := rule.Labels[constants.RuleLabelStatus]
				assert.False(t, hasStatus)
			},
		},
		{
			name: "group with external labels",
			templateRules: vmv1beta1.VMRuleSpec{
				Groups: []vmv1beta1.RuleGroup{
					{
						Name:     "group1",
						Interval: "30s",
						Rules: []vmv1beta1.Rule{
							{
								Alert: "TestAlert",
								Expr:  "up == 0",
								Labels: map[string]string{
									constants.RuleLabelID:         "rule-1",
									constants.RuleLabelStatus:     string(constants.RULE_ACTIVE),
									constants.RuleLabelVisibility: "internal",
								},
							},
						},
					},
				},
			},
			overlayRules: vmv1beta1.VMRuleSpec{
				Groups: []vmv1beta1.RuleGroup{},
			},
			cluster: &observabilitypingcapcomv1.Cluster{
				ObjectMeta: metav1.ObjectMeta{
					Labels: map[string]string{
						constants.LabelTenantID:      "tenant-1",
						constants.LabelProjectID:     "project-1",
						constants.LabelApplicationID: "app-1",
						constants.LabelBizType:       "test-biz",
						constants.LabelVendor:        "aws",
						constants.LabelRegion:        "us-west-2",
					},
				},
				Spec: observabilitypingcapcomv1.ClusterSpec{
					VictoriaAccount: observabilitypingcapcomv1.VictoriaAccount{
						AccountID: 123,
						ProjectID: 456,
					},
				},
			},
			expectedLen: 1,
			validate: func(t *testing.T, result vmv1beta1.VMRuleSpec) {
				assert.Equal(t, 1, len(result.Groups))
				group := result.Groups[0]

				// Check group properties
				assert.Equal(t, "123:456", group.Tenant)
				assert.Equal(t, constants.VMRuleGroupDefaultConcurrency, group.Concurrency)

				// Check external labels
				assert.Equal(t, "test-biz", group.Labels[constants.ExternalLabelBizType])
				assert.Equal(t, "aws-us-west-2", group.Labels[constants.ExternalLabelRegion])
				assert.Equal(t, "tenant-1", group.Labels[constants.ExternalLabelTenantID])
				assert.Equal(t, "app-1", group.Labels[constants.ExternalLabelTiDBClusterID])
				assert.Equal(t, "project-1", group.Labels[constants.ExternalLabelProjectID])
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := alertRuleMerge(tt.templateRules, tt.overlayRules, tt.cluster)
			if tt.validate != nil {
				tt.validate(t, result)
			}
		})
	}
}

func TestReplaceExternalRulePlaceHolder(t *testing.T) {
	tests := []struct {
		name         string
		rule         vmv1beta1.Rule
		expectedExpr string
		validateFunc func(t *testing.T, result vmv1beta1.Rule)
	}{
		{
			name: "replace all placeholders",
			rule: vmv1beta1.Rule{
				Alert: "Alert-{severity}",
				Expr:  "cpu_usage > 0.8",
				For:   "5m",
				Labels: map[string]string{
					constants.RuleLabelSeverity:          "critical",
					constants.RuleAnnotationsMessage:     "Message with {threshold}",
					constants.RuleAnnotationsDescription: "Description with {severity}",
				},
				Annotations: map[string]string{
					constants.RuleAnnotationsMessage:     "CPU usage exceeds {threshold}",
					constants.RuleAnnotationsDescription: "Severity: {severity}, Duration: {triggerInterval} min",
					constants.RuleAnnotationsSummary:     "Threshold: {thresholdPercentage}%",
				},
			},
			validateFunc: func(t *testing.T, result vmv1beta1.Rule) {
				assert.Contains(t, result.Alert, "critical")
				assert.NotContains(t, result.Alert, "{severity}")

				assert.Contains(t, result.Annotations[constants.RuleAnnotationsMessage], "0.8")
				assert.NotContains(t, result.Annotations[constants.RuleAnnotationsMessage], "{threshold}")

				assert.Contains(t, result.Annotations[constants.RuleAnnotationsDescription], "critical")
				assert.Contains(t, result.Annotations[constants.RuleAnnotationsDescription], "5")

				assert.Contains(t, result.Annotations[constants.RuleAnnotationsSummary], "80")
			},
		},
		{
			name: "replace with decimal threshold",
			rule: vmv1beta1.Rule{
				Alert: "MemoryAlert",
				Expr:  "memory_usage >= 0.95",
				For:   "10m",
				Labels: map[string]string{
					constants.RuleLabelSeverity: "warning",
				},
				Annotations: map[string]string{
					constants.RuleAnnotationsMessage: "Memory at {thresholdPercentage}%",
				},
			},
			validateFunc: func(t *testing.T, result vmv1beta1.Rule) {
				assert.Contains(t, result.Annotations[constants.RuleAnnotationsMessage], "95")
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := replaceExternalRulePlaceHolder(tt.rule)
			if tt.validateFunc != nil {
				tt.validateFunc(t, result)
			}
		})
	}
}

func TestReplaceByPlaceHold(t *testing.T) {
	tests := []struct {
		name                 string
		src                  string
		placeholderVariables map[string]string
		expected             string
	}{
		{
			name: "replace single placeholder",
			src:  "The threshold is {threshold}",
			placeholderVariables: map[string]string{
				constants.PlaceHolderThreshold: "0.8",
			},
			expected: "The threshold is 0.8",
		},
		{
			name: "replace multiple placeholders",
			src:  "Severity: {severity}, Threshold: {threshold}%, Duration: {triggerInterval} min",
			placeholderVariables: map[string]string{
				constants.PlaceHolderSeverity:       "critical",
				constants.PlaceHolderThreshold:      "0.9",
				constants.PlaceHolderTriggerInteval: "5",
			},
			expected: "Severity: critical, Threshold: 0.9%, Duration: 5 min",
		},
		{
			name: "no placeholders to replace",
			src:  "This is a plain string",
			placeholderVariables: map[string]string{
				constants.PlaceHolderThreshold: "0.8",
			},
			expected: "This is a plain string",
		},
		{
			name: "placeholder not in map",
			src:  "The threshold is {threshold} and severity is {severity}",
			placeholderVariables: map[string]string{
				constants.PlaceHolderThreshold: "0.8",
			},
			expected: "The threshold is 0.8 and severity is {severity}",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := replaceByPlaceHold(tt.src, tt.placeholderVariables)
			assert.Equal(t, tt.expected, result)
		})
	}
}
