package resourcemanager

import (
	"context"
	"testing"

	prometheusv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
	"k8s.io/apimachinery/pkg/util/intstr"

	"github.com/tidbcloud/observability/pkg/common/errors"

	"github.com/tidbcloud/observability/pkg/common/constants"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"github.com/stretchr/testify/assert"
)

func mockPrometheusRule(id string, tenantID, projectID string) *prometheusv1.PrometheusRule {
	return &prometheusv1.PrometheusRule{
		ObjectMeta: metav1.ObjectMeta{
			Name:      id,
			Namespace: "default-" + tenantID,
			Labels: map[string]string{
				constants.LabelClusterID:     id,
				constants.LabelVendor:        "aws",
				constants.LabelRegion:        "us-east-2",
				constants.LabelTenantID:      tenantID,
				constants.LabelProjectID:     projectID,
				constants.LabelApplicationID: "default",
				constants.LabelBizType:       "default",
			},
			Annotations: map[string]string{
				constants.AnnotationNote: "note111",
			},
		},
		Spec: prometheusv1.PrometheusRuleSpec{
			Groups: []prometheusv1.RuleGroup{
				0: {
					Name:     "example",
					Interval: "5",
					Rules: []prometheusv1.Rule{
						{
							Alert: "HighRequestLatency",
							Expr:  intstr.FromString("request_latency_seconds:mean5m{job=\"myjob\"} > 0.5"),
							For:   "10m",
							Labels: map[string]string{
								"severity": "critical",
							},
							Annotations: map[string]string{
								"summary": "High request latency",
							},
						},
					},
				},
			},
		},
	}
}

func Test_CreateAndDeletePrometheusRule(t *testing.T) {
	prometheusRuleRW.Create(context.TODO(), mockPrometheusRule(defaultClusterID, "default", "defaultProject"))
	defer prometheusRuleRW.DeletePrometheusRules(context.TODO(), defaultClusterID)
	clusterID := "newCluster"
	_, err := prometheusRuleRW.GetPrometheusRule(context.TODO(), clusterID)
	assert.Error(t, err)
	assert.Equal(t, errors.PrometheusRuleNotFound, err.(errors.Error).Code())

	exists, err := prometheusRuleRW.IsPrometheusRuleIDExists(context.TODO(), clusterID)
	assert.NoError(t, err)
	assert.False(t, exists)

	exists, err = prometheusRuleRW.IsPrometheusRuleIDExists(context.TODO(), defaultClusterID)
	assert.NoError(t, err)
	assert.True(t, exists)

}

func Test_UpdatePrometheusRule(t *testing.T) {
	prometheusRuleRW.Create(context.TODO(), mockPrometheusRule("updateID", "default", "updateID"))
	defer prometheusRuleRW.DeletePrometheusRules(context.TODO(), "updateID")

	result, err := prometheusRuleRW.GetPrometheusRule(context.TODO(), "updateID")
	assert.NoError(t, err)
	assert.Equal(t, "updateID", result.Labels[constants.LabelProjectID])
	assert.Equal(t, "note111", result.Annotations[constants.AnnotationNote])

	result.Annotations[constants.AnnotationNote] = "newNote"

	err = prometheusRuleRW.UpdatePrometheusRule(context.TODO(), result)
	assert.NoError(t, err)

	result, err = prometheusRuleRW.GetPrometheusRule(context.TODO(), "updateID")
	assert.NoError(t, err)
	assert.Equal(t, "updateID", result.Labels[constants.LabelProjectID])
	assert.Equal(t, "newNote", result.Annotations[constants.AnnotationNote])
}

func Test_QueryPrometheusRule(t *testing.T) {
	promRule1 := mockPrometheusRule("cluster1", "default", "project1")
	prometheusRuleRW.Create(context.TODO(), promRule1)
	defer prometheusRuleRW.DeletePrometheusRules(context.TODO(), "cluster1")

	t.Run("query", func(t *testing.T) {
		result, err := prometheusRuleRW.GetPrometheusRule(context.TODO(), "cluster1")
		assert.NoError(t, err)
		assert.Equal(t, 1, len(result.Spec.Groups))
	})

}

func Test_ListPrometheusRulesInNs(t *testing.T) {
	promRule1 := mockPrometheusRule("cluster1", "default", "project1")
	prometheusRuleRW.Create(context.TODO(), promRule1)
	defer prometheusRuleRW.DeletePrometheusRules(context.TODO(), "cluster1")

	t.Run("list", func(t *testing.T) {
		result, err := prometheusRuleRW.ListPrometheusRulesInNs(context.TODO(), "default-default")
		assert.NoError(t, err)
		assert.Equal(t, 1, len(result[0].Spec.Groups))
	})

	t.Run("empty", func(t *testing.T) {
		result, err := prometheusRuleRW.ListPrometheusRulesInNs(context.TODO(), "default-empty")
		assert.NoError(t, err)
		assert.Equal(t, 0, len(result))
	})

}
