package regionalapi

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	prometheusv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
	"github.com/stretchr/testify/assert"
	"github.com/tidbcloud/observability/pkg/common/constants"
	"github.com/tidbcloud/observability/pkg/common/errors"
	"github.com/tidbcloud/observability/pkg/common/message"
	"github.com/tidbcloud/observability/pkg/resourcemanager"
	"github.com/tidbcloud/observability/test/mockresourcemanager"
	"go.uber.org/mock/gomock"
)

func TestOpenCreateCluster(t *testing.T) {
	body, _ := json.Marshal(message.OpenCreateClusterRequest{
		ProjectID:       "1",
		ApplicationID:   "1",
		ShareMode:       constants.SHARED,
		AgentAccessARN:  "arn",
		AgentManagerARN: "arn",
	})
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	clusterRW := mockresourcemanager.NewMockClusterReaderWriter(ctrl)
	resourcemanager.MockClusterReaderWriter(clusterRW)
	clusterRW.EXPECT().QueryClusters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New(errors.ParameterInvalid, "")).Times(1)
	w := httptest.NewRecorder()

	req, _ := http.NewRequest("POST", "/api/v2/observability/clusters/", strings.NewReader(string(body)))
	req.Header.Set(string(constants.OpenAPIHeaderAuthorization), fmt.Sprintf("%s %s", constants.BearerPrefix, stsToken))
	req.Header.Set(string(constants.OpenAPIHeaderOrgId), "111")
	req.Header.Set(string(constants.OpenAPIHeaderVendor), "aws")
	req.Header.Set(string(constants.OpenAPIHeaderRegion), "us-west-2")
	req.Header.Set(string(constants.OpenAPIHeaderBizType), "byoc")

	testEngine.ServeHTTP(w, req)
	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestOpenDetailCluster(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	clusterRW := mockresourcemanager.NewMockClusterReaderWriter(ctrl)
	resourcemanager.MockClusterReaderWriter(clusterRW)
	clusterRW.EXPECT().GetCluster(gomock.Any(), gomock.Any()).Return(nil, errors.New(errors.ParameterInvalid, "")).Times(1)
	w := httptest.NewRecorder()

	req, _ := http.NewRequest("GET", "/api/v2/observability/clusters/aaa", nil)
	req.Header.Set(string(constants.OpenAPIHeaderAuthorization), fmt.Sprintf("%s %s", constants.BearerPrefix, stsToken))
	req.Header.Set(string(constants.OpenAPIHeaderOrgId), "111")
	req.Header.Set(string(constants.OpenAPIHeaderVendor), "aws")
	req.Header.Set(string(constants.OpenAPIHeaderRegion), "us-west-2")
	req.Header.Set(string(constants.OpenAPIHeaderBizType), "byoc")
	testEngine.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestOpenDeleteCluster(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	clusterRW := mockresourcemanager.NewMockClusterReaderWriter(ctrl)
	resourcemanager.MockClusterReaderWriter(clusterRW)
	clusterRW.EXPECT().GetCluster(gomock.Any(), gomock.Any()).Return(nil, errors.New(errors.ParameterInvalid, "")).Times(1)
	w := httptest.NewRecorder()

	req, _ := http.NewRequest("DELETE", "/api/v2/observability/clusters/aaa", nil)
	req.Header.Set(string(constants.OpenAPIHeaderAuthorization), fmt.Sprintf("%s %s", constants.BearerPrefix, stsToken))
	req.Header.Set(string(constants.OpenAPIHeaderOrgId), "111")
	req.Header.Set(string(constants.OpenAPIHeaderVendor), "aws")
	req.Header.Set(string(constants.OpenAPIHeaderRegion), "us-west-2")
	req.Header.Set(string(constants.OpenAPIHeaderBizType), "byoc")
	testEngine.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestOpenPauseCluster(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	clusterRW := mockresourcemanager.NewMockClusterReaderWriter(ctrl)
	resourcemanager.MockClusterReaderWriter(clusterRW)
	clusterRW.EXPECT().GetCluster(gomock.Any(), gomock.Any()).Return(nil, errors.New(errors.ParameterInvalid, "")).Times(1)
	w := httptest.NewRecorder()

	req, _ := http.NewRequest("POST", "/api/v2/observability/clusters/aaa/pause", nil)
	req.Header.Set(string(constants.OpenAPIHeaderAuthorization), fmt.Sprintf("%s %s", constants.BearerPrefix, stsToken))
	req.Header.Set(string(constants.OpenAPIHeaderOrgId), "111")
	req.Header.Set(string(constants.OpenAPIHeaderVendor), "aws")
	req.Header.Set(string(constants.OpenAPIHeaderRegion), "us-west-2")
	req.Header.Set(string(constants.OpenAPIHeaderBizType), "byoc")
	testEngine.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestOpenResumeCluster(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	clusterRW := mockresourcemanager.NewMockClusterReaderWriter(ctrl)
	resourcemanager.MockClusterReaderWriter(clusterRW)
	clusterRW.EXPECT().GetCluster(gomock.Any(), gomock.Any()).Return(nil, errors.New(errors.ParameterInvalid, "")).Times(1)
	w := httptest.NewRecorder()

	req, _ := http.NewRequest("POST", "/api/v2/observability/clusters/aaa/resume", nil)
	req.Header.Set(string(constants.OpenAPIHeaderAuthorization), fmt.Sprintf("%s %s", constants.BearerPrefix, stsToken))
	req.Header.Set(string(constants.OpenAPIHeaderOrgId), "111")
	req.Header.Set(string(constants.OpenAPIHeaderVendor), "aws")
	req.Header.Set(string(constants.OpenAPIHeaderRegion), "us-west-2")
	req.Header.Set(string(constants.OpenAPIHeaderBizType), "byoc")
	testEngine.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestOpenQueryClusters(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	clusterRW := mockresourcemanager.NewMockClusterReaderWriter(ctrl)
	resourcemanager.MockClusterReaderWriter(clusterRW)
	clusterRW.EXPECT().QueryClusters(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New(errors.ParameterInvalid, "")).Times(1)
	w := httptest.NewRecorder()

	req, _ := http.NewRequest("GET", "/api/v2/observability/clusters/", nil)
	req.Header.Set(string(constants.OpenAPIHeaderAuthorization), fmt.Sprintf("%s %s", constants.BearerPrefix, stsToken))
	req.Header.Set(string(constants.OpenAPIHeaderOrgId), "111")
	req.Header.Set(string(constants.OpenAPIHeaderVendor), "aws")
	req.Header.Set(string(constants.OpenAPIHeaderRegion), "us-west-2")
	req.Header.Set(string(constants.OpenAPIHeaderBizType), "byoc")
	testEngine.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestListTemplates(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	rw := mockresourcemanager.NewMockPrometheusRuleReaderWriter(ctrl)
	resourcemanager.MockPrometheusRuleReaderWriter(rw)
	resourcemanager.MockVMRuleReaderWriter(rw)
	rw.EXPECT().ListPrometheusRulesInNs(gomock.Any(), gomock.Any()).Return([]*prometheusv1.PrometheusRule{}, errors.New(errors.ParameterInvalid, "")).Times(1)
	w := httptest.NewRecorder()

	req, _ := http.NewRequest("GET", "/api/v2/observability/alertrule/templates/", nil)
	req.Header.Set(string(constants.OpenAPIHeaderAuthorization), fmt.Sprintf("%s %s", constants.BearerPrefix, stsToken))
	req.Header.Set(string(constants.OpenAPIHeaderOrgId), "111")
	req.Header.Set(string(constants.OpenAPIHeaderVendor), "aws")
	req.Header.Set(string(constants.OpenAPIHeaderRegion), "us-west-2")
	req.Header.Set(string(constants.OpenAPIHeaderBizType), "byoc")
	testEngine.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestGetTemplates(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	rw := mockresourcemanager.NewMockPrometheusRuleReaderWriter(ctrl)
	resourcemanager.MockPrometheusRuleReaderWriter(rw)
	resourcemanager.MockVMRuleReaderWriter(rw)
	rw.EXPECT().GetPrometheusRule(gomock.Any(), gomock.Any()).Return(&prometheusv1.PrometheusRule{}, errors.New(errors.ParameterInvalid, "")).Times(1)
	w := httptest.NewRecorder()

	req, _ := http.NewRequest("GET", "/api/v2/observability/alertrule/templates/aaaa", nil)
	req.Header.Set(string(constants.OpenAPIHeaderAuthorization), fmt.Sprintf("%s %s", constants.BearerPrefix, stsToken))
	req.Header.Set(string(constants.OpenAPIHeaderOrgId), "111")
	req.Header.Set(string(constants.OpenAPIHeaderVendor), "aws")
	req.Header.Set(string(constants.OpenAPIHeaderRegion), "us-west-2")
	req.Header.Set(string(constants.OpenAPIHeaderBizType), "byoc")
	testEngine.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}

func TestClusterRule(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	rw := mockresourcemanager.NewMockPrometheusRuleReaderWriter(ctrl)
	resourcemanager.MockPrometheusRuleReaderWriter(rw)
	resourcemanager.MockVMRuleReaderWriter(rw)
	rw.EXPECT().GetPrometheusRule(gomock.Any(), gomock.Any()).Return(&prometheusv1.PrometheusRule{}, errors.New(errors.ParameterInvalid, "")).Times(1)
	w := httptest.NewRecorder()

	req, _ := http.NewRequest("GET", "/api/v2/observability/clusters/aaa/alertrule/", nil)
	req.Header.Set(string(constants.OpenAPIHeaderAuthorization), fmt.Sprintf("%s %s", constants.BearerPrefix, stsToken))
	req.Header.Set(string(constants.OpenAPIHeaderOrgId), "111")
	req.Header.Set(string(constants.OpenAPIHeaderVendor), "aws")
	req.Header.Set(string(constants.OpenAPIHeaderRegion), "us-west-2")
	req.Header.Set(string(constants.OpenAPIHeaderBizType), "byoc")
	testEngine.ServeHTTP(w, req)

	assert.Equal(t, http.StatusBadRequest, w.Code)
}
