package globalapi

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"

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

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

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"github.com/tidbcloud/observability/pkg/common/structs"
)

func mockCPUAlertReq(id string) message.GlobalHandleAlertReq {
	return message.GlobalHandleAlertReq{
		Status: "firing",
		Alerts: []structs.Alert{
			{
				Status: "firing",
				Labels: map[string]string{
					"alertname":              "PrometheusCPUThrottlingHigh",
					constants.O11YK8SIDLabel: "o11y-prod-regional-us-west-2-primary",
					"component":              "observability-regional-server",
					"namespace":              "test-ns",
					"pod":                    "prometheus-" + id + "-0",
					"severity":               "critical",
					"container":              "prometheus",
				},
				Annotations: map[string]string{},
			},
		},
	}
}

func mockMemoryAlertReq(id string) message.GlobalHandleAlertReq {
	return message.GlobalHandleAlertReq{
		Status: "firing",
		GroupLabels: map[string]string{
			"test": "test",
		},
		Alerts: []structs.Alert{
			{
				Status: "firing",
				Labels: map[string]string{
					"alertname":              "O11yPodMemoryFillingUp",
					constants.O11YK8SIDLabel: "o11y-prod-regional-us-west-2-primary",
					"component":              "observability-regional-server",
					"namespace":              "test-ns",
					"pod":                    "prometheus-" + id + "-0",
					"severity":               "critical",
					"container":              "prometheus",
				},
				Annotations: map[string]string{
					"test": "test",
				},
			},
		},
	}
}

func mockStorageAlertReq(id string) message.GlobalHandleAlertReq {
	return message.GlobalHandleAlertReq{
		Status: "firing",
		Alerts: []structs.Alert{
			{
				Status: "firing",
				Labels: map[string]string{
					"alertname":              "KubePersistentVolumeFillingUp",
					constants.O11YK8SIDLabel: "o11y-prod-regional-us-west-2-primary",
					"component":              "observability-regional-server",
					"endpoint":               "https-metrics",
					"instance":               "10.0.56.142:10250",
					"job":                    "kubelet",
					"metrics_path":           "/metrics",
					"namespace":              "test-ns",
					"node":                   "ip-10-0-56-142.ec2.internal",
					"persistentvolumeclaim":  "prometheus-" + id + "-db-prometheus-" + id + "-0",
					"severity":               "warning",
				},
				Annotations: map[string]string{},
			},
		},
	}
}

func mockOtherMemoryAlertReq() message.GlobalHandleAlertReq {
	return message.GlobalHandleAlertReq{
		Status: "firing",
		Alerts: []structs.Alert{
			{
				Status: "firing",
				Labels: map[string]string{
					"alertname":              "O11yPodMemoryFillingUp",
					constants.O11YK8SIDLabel: "o11y-prod-regional-us-west-2-primary",
					"component":              "observability-regional-server",
					"namespace":              "monitoring-system",
					"pod":                    "vm-operator-76b86d6f99-rn4hf",
					"severity":               "critical",
					"prometheus":             "self-monitoring/self-monitoring-kube-prome-prometheus",
				},
				Annotations: map[string]string{
					"test": "test",
				},
			},
		},
	}
}

func TestHandleAlerts(t *testing.T) {
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)

	// set context
	c.Set(structs.GlobalServerRequestParametersKey, requestParameters)
	req := message.GlobalHandleAlertReq{
		Status: "firing",
		Alerts: []structs.Alert{},
	}
	t.Setenv("AWS_ROLE_ARN", "arn:aws:iam::1234567890:role/test")
	t.Setenv("AWS_WEB_IDENTITY_TOKEN_FILE", "./clusterapi_test.go")
	t.Setenv("AWS_REGION", "us-west-2")

	t.Run("empty alert", func(t *testing.T) {
		body, err := json.Marshal(req)
		assert.NoError(t, err)
		c.Request = &http.Request{
			Method: http.MethodPost,
			Body:   ioutil.NopCloser(bytes.NewReader(body)),
		}
		HandleAlerts(c)
		assert.Equal(t, http.StatusOK, w.Code)
		assert.Empty(t, w.Body.String())
	})
	t.Run("cpu alert", func(t *testing.T) {
		req = mockCPUAlertReq("aaa")
		body, err := json.Marshal(req)
		assert.NoError(t, err)
		c.Request = &http.Request{
			Method: http.MethodPost,
			Body:   ioutil.NopCloser(bytes.NewReader(body)),
		}
		HandleAlerts(c)

		assert.Equal(t, http.StatusOK, w.Code)
		assert.NotEmpty(t, w.Body.String())
	})
	t.Run("memory alert", func(t *testing.T) {
		req = mockMemoryAlertReq("aaa")
		body, err := json.Marshal(req)
		assert.NoError(t, err)
		c.Request = &http.Request{
			Method: http.MethodPost,
			Body:   ioutil.NopCloser(bytes.NewReader(body)),
		}
		HandleAlerts(c)

		assert.Equal(t, http.StatusOK, w.Code)
		assert.NotEmpty(t, w.Body.String())
	})
	t.Run("storage alert", func(t *testing.T) {
		req = mockStorageAlertReq("dbbbb")
		body, err := json.Marshal(req)
		assert.NoError(t, err)
		c.Request = &http.Request{
			Method: http.MethodPost,
			Body:   ioutil.NopCloser(bytes.NewReader(body)),
		}
		HandleAlerts(c)

		assert.Equal(t, http.StatusOK, w.Code)
		assert.NotEmpty(t, w.Body.String())
	})
	t.Run("other alert", func(t *testing.T) {
		req = mockOtherMemoryAlertReq()
		body, err := json.Marshal(req)
		assert.NoError(t, err)
		c.Request = &http.Request{
			Method: http.MethodPost,
			Body:   ioutil.NopCloser(bytes.NewReader(body)),
		}
		HandleAlerts(c)

		assert.Equal(t, http.StatusOK, w.Code)
		assert.NotEmpty(t, w.Body.String())
	})

}
