package regionalapi

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/observability/pkg/common/errors"
	"github.com/tidbcloud/observability/pkg/common/message"
	"github.com/tidbcloud/observability/pkg/regionalapi/apiinterceptor"
	"github.com/tidbcloud/observability/pkg/regionalservice"
)

// OpenCreateCluster
// @Summary Create an observability cluster
// @Tags Cluster
// @Accept json
// @Produce json
// @Param x-vendor header string true "Cloud vendor" enum(aws,gcp,azure)
// @Param x-region header string true "Region"
// @Param x-org-id header string true "Organization ID"
// @Param request body message.OpenCreateClusterRequest true "Create request"
// @Success 202 {object} message.Result{data=message.OpenObservabilityCluster}
// @Success 409 {object} message.Result{data=message.OpenObservabilityCluster}
// @Failure 500 {object} message.Result
// @Router /api/v2/observability/clusters/ [post]
func OpenCreateCluster(c *gin.Context) {
	var openReq message.OpenCreateClusterRequest
	var headers message.OpenCommonHeaders

	if apiinterceptor.HandleJsonRequestFromBody(c, &openReq) && apiinterceptor.HandleHeaders(c, &headers) {
		req := message.OpenConvertCreateReq(c, openReq, headers)

		resp, err := regionalservice.GetHandler().CreateCluster(c, req)
		if err != nil {
			if err.(errors.Error).Code() == errors.DuplicatedCluster {
				openResp := message.OpenConvertCluster(c, resp.ObservabilityCluster)
				apiinterceptor.Succeed(c, http.StatusConflict, openResp)
			} else {
				apiinterceptor.Fail(c, err)
			}
		} else {
			openResp := message.OpenConvertCluster(c, resp.ObservabilityCluster)
			apiinterceptor.Succeed(c, http.StatusAccepted, openResp)
		}
	}
}

// OpenGetClusterList
// @Summary Query cluster list
// @Tags Cluster
// @Produce json
// @Param x-vendor header string true "Cloud vendor" enum(aws,gcp,azure)
// @Param x-region header string true "Region"
// @Param x-org-id header string true "Organization ID"
// @Param projectID query string false "Project ID"
// @Param applicationID query string false "Application ID"
// @Success 200 {object} message.Result{data=message.OpenClusterListResponse}
// @Router /api/v2/observability/clusters/ [get]
func OpenGetClusterList(c *gin.Context) {
	var openReq message.OpenClusterListReq
	var headers message.OpenCommonHeaders

	if ok := apiinterceptor.HandleJsonRequestFromQuery(c, &openReq) && apiinterceptor.HandleHeaders(c, &headers); ok {
		req := message.OpenConvertListReq(c, openReq, headers)

		resp, err := regionalservice.GetHandler().QueryClusters(c, req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			openResp := message.OpenConvertClusters(c, resp)
			apiinterceptor.Succeed(c, http.StatusOK, openResp)
		}
	}
}

// OpenGetClusterDetail
// @Summary Get cluster details
// @Tags Cluster
// @Produce json
// @Param x-vendor header string true "Cloud vendor" enum(aws,gcp,azure)
// @Param x-region header string true "Region"
// @Param x-org-id header string true "Organization ID"
// @Param cluster_id path string true "Cluster ID"
// @Success 200 {object} message.Result{data=message.OpenObservabilityCluster}
// @Failure 404 {object} message.Result
// @Router /api/v2/observability/clusters/{cluster_id} [get]
func OpenGetClusterDetail(c *gin.Context) {
	openReq := message.OpenDetailClusterReq{
		ID: c.Param("cluster_id"),
	}
	var headers message.OpenCommonHeaders
	if ok := apiinterceptor.HandleJsonRequestFromQuery(c, &openReq) && apiinterceptor.HandleHeaders(c, &headers); ok {
		// TODO openapi validate the cluster and tenant
		resp, err := regionalservice.GetHandler().GetClusterDetail(c, message.OpenConvertDetailReq(c, openReq, headers))

		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			openResp := message.OpenConvertCluster(c, resp.ObservabilityCluster)
			if err != nil {
				apiinterceptor.Fail(c, err)
			}
			apiinterceptor.Succeed(c, http.StatusOK, openResp)
		}
	}
}

// OpenDeleteCluster
// @Summary Delete cluster
// @Tags Cluster
// @Produce json
// @Param x-vendor header string true "Cloud vendor" enum(aws,gcp,azure)
// @Param x-region header string true "Region"
// @Param x-org-id header string true "Organization ID"
// @Param cluster_id path string true "Cluster ID"
// @Success 202 {object} message.Result{data=message.OpenObservabilityCluster}
// @Failure 404 {object} message.Result
// @Router /api/v2/observability/clusters/{cluster_id} [delete]
func OpenDeleteCluster(c *gin.Context) {
	openReq := message.OpenDeleteClusterReq{
		ID: c.Param("cluster_id"),
	}
	var headers message.OpenCommonHeaders
	if ok := apiinterceptor.HandleJsonRequestFromQuery(c, &openReq) && apiinterceptor.HandleHeaders(c, &headers); ok {
		// TODO openapi validate the cluster and tenant
		resp, err := regionalservice.GetHandler().DeleteCluster(c, message.OpenConvertDeleteReq(c, openReq, headers))

		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			openResp := message.OpenConvertClusterBaseInfo(c, resp.ClusterBaseInfo)
			apiinterceptor.Succeed(c, http.StatusAccepted, openResp)
		}
	}
}

// OpenPauseCluster
// @Summary Pause cluster
// @Tags Cluster
// @Produce json
// @Param x-vendor header string true "Cloud vendor" enum(aws,gcp,azure)
// @Param x-region header string true "Region"
// @Param x-org-id header string true "Organization ID"
// @Param cluster_id path string true "Cluster ID"
// @Success 202 {object} message.Result{data=message.OpenObservabilityCluster}
// @Failure 404 {object} message.Result
// @Router /api/v2/observability/clusters/{cluster_id}/pause [post]
func OpenPauseCluster(c *gin.Context) {
	openReq := message.OpenPauseClusterReq{
		ID: c.Param("cluster_id"),
	}
	var headers message.OpenCommonHeaders
	if ok := apiinterceptor.HandleJsonRequestFromQuery(c, &openReq) && apiinterceptor.HandleHeaders(c, &headers); ok {
		// TODO openapi validate the cluster and tenant
		resp, err := regionalservice.GetHandler().PauseCluster(c, message.OpenConvertPauseReq(c, openReq, headers))

		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			openResp := message.OpenConvertClusterBaseInfo(c, resp.ClusterBaseInfo)
			apiinterceptor.Succeed(c, http.StatusAccepted, openResp)
		}
	}
}

// OpenResumeCluster
// @Summary Resume cluster
// @Tags Cluster
// @Produce json
// @Param x-vendor header string true "Cloud vendor" enum(aws,gcp,azure)
// @Param x-region header string true "Region"
// @Param x-org-id header string true "Organization ID"
// @Param cluster_id path string true "Cluster ID"
// @Success 202 {object} message.Result{data=message.OpenObservabilityCluster}
// @Failure 400 {object} message.Result
// @Failure 401 {object} message.Result
// @Failure 403 {object} message.Result
// @Failure 404 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /api/v2/observability/clusters/{cluster_id}/resume [post]
func OpenResumeCluster(c *gin.Context) {
	openReq := message.OpenResumeClusterReq{
		ID: c.Param("cluster_id"),
	}
	var headers message.OpenCommonHeaders
	if ok := apiinterceptor.HandleJsonRequestFromQuery(c, &openReq) && apiinterceptor.HandleHeaders(c, &headers); ok {
		// TODO openapi validate the cluster and tenant
		resp, err := regionalservice.GetHandler().ResumeCluster(c, message.OpenConvertResumeReq(c, openReq, headers))

		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			openResp := message.OpenConvertClusterBaseInfo(c, resp.ClusterBaseInfo)
			apiinterceptor.Succeed(c, http.StatusAccepted, openResp)
		}
	}
}

// OpenUpdateCategoryConfig
// @Summary Update category configuration
// @Tags Cluster
// @Accept json
// @Produce json
// @Param x-vendor header string true "Cloud vendor" enum(aws,gcp,azure)
// @Param x-region header string true "Region"
// @Param x-org-id header string true "Organization ID"
// @Param cluster_id path string true "Cluster ID"
// @Param module path string true "Module name" enum(logs,metrics,topsql,slowlog,profile,key_visualizer)
// @Param request body message.OpenModuleConfigRequest true "Configuration"
// @Success 200 {object} message.Result
// @Router /api/v2/observability/clusters/{cluster_id}/{category}/config [put]
func OpenUpdateCategoryConfig(c *gin.Context) {
	apiinterceptor.Fail(c, errors.New(errors.APINotFound, "api not supported yet"))
}

// OpenUpdateCategoryStatus
// @Summary Update category status
// @Tags Cluster
// @Accept json
// @Produce json
// @Param x-vendor header string true "Cloud vendor" enum(aws,gcp,azure)
// @Param x-region header string true "Region"
// @Param x-org-id header string true "Organization ID"
// @Param cluster_id path string true "Cluster ID"
// @Param category path string true "category name" enum(logs,metrics,alerts,topsql,slowlog,profile,key_visualizer)
// @Param request body message.OpenModuleStatusRequest true "Status"
// @Success 200 {object} message.Result
// @Router /api/v2/observability/clusters/{cluster_id}/{category}/status [put]
func OpenUpdateCategoryStatus(c *gin.Context) {
	apiinterceptor.Fail(c, errors.New(errors.APINotFound, "api not supported yet"))
}

// OpenGetAlertRuleTemplates
// @Summary Get alert rule templates
// @Tags AlertRule
// @Produce json
// @Param x-vendor header string true "Cloud vendor" enum(aws,gcp,azure)
// @Param x-region header string true "Region"
// @Param x-org-id header string true "Organization ID"
// @Success 200 {object} message.Result{data=message.OpenAlertRuleTemplateList}
// @Router /api/v2/observability/alertrule/templates/ [get]
func OpenGetAlertRuleTemplates(c *gin.Context) {
	resp, err := regionalservice.GetTemplateHandler().ListRuleTemplates(c)
	if err != nil {
		apiinterceptor.Fail(c, err)
	} else {
		apiinterceptor.Succeed(c, http.StatusAccepted, resp)
	}
}

// OpenGetAlertRuleTemplateDetail
// @Summary Get alert rule template detail
// @Tags AlertRule
// @Produce json
// @Param x-vendor header string true "Cloud vendor" enum(aws,gcp,azure)
// @Param x-region header string true "Region"
// @Param x-org-id header string true "Organization ID"
// @Param template_id path string true "Template ID"
// @Success 200 {object} message.Result{data=message.OpenAlertRule}
// @Failure 404 {object} message.Result
// @Router /api/v2/observability/alertrule/templates/{template_id} [get]
func OpenGetAlertRuleTemplateDetail(c *gin.Context) {
	templateID := c.Param("template_id")
	if len(templateID) == 0 {
		apiinterceptor.Fail(c, errors.New(errors.ParameterInvalid, "template_id required"))
	}

	resp, err := regionalservice.GetTemplateHandler().GetRuleTemplate(c, templateID)
	if err != nil {
		apiinterceptor.Fail(c, err)
	} else {
		apiinterceptor.Succeed(c, http.StatusAccepted, resp)
	}
}

// OpenGetClusterAlertRule
// @Summary Get alert rule template detail
// @Tags AlertRule
// @Produce json
// @Param x-vendor header string true "Cloud vendor" enum(aws,gcp,azure)
// @Param x-region header string true "Region"
// @Param x-org-id header string true "Organization ID"
// @Param cluster_id path string true "cluster ID"
// @Success 200 {object} message.Result{data=message.OpenAlertRule}
// @Failure 404 {object} message.Result
// @Router /api/v2/observability/clusters/{cluster_id}/alertrule/ [get]
func OpenGetClusterAlertRule(c *gin.Context) {
	clusterID := c.Param("cluster_id")
	if len(clusterID) == 0 {
		apiinterceptor.Fail(c, errors.New(errors.ParameterInvalid, "cluster id required"))
	}

	resp, err := regionalservice.GetHandler().GetFullPrometheusRule(c, clusterID)
	if err != nil {
		apiinterceptor.Fail(c, err)
	} else {
		apiinterceptor.Succeed(c, http.StatusAccepted, resp)
	}
}

// OpenUpdateClusterAlertRule
// @Summary Get alert rule template detail
// @Tags AlertRule
// @Produce json
// @Param x-vendor header string true "Cloud vendor" enum(aws,gcp,azure)
// @Param x-region header string true "Region"
// @Param x-org-id header string true "Organization ID"
// @Param cluster_id path string true "cluster ID"
// @Param alert_rules body message.OpenAlertRule true "content"
// @Success 200 {object} message.Result{data=message.OpenAlertRule}
// @Failure 404 {object} message.Result
// @Router /api/v2/observability/clusters/{cluster_id}/alertrule/ [put]
func OpenUpdateClusterAlertRule(c *gin.Context) {
	clusterID := c.Param("cluster_id")
	if len(clusterID) == 0 {
		apiinterceptor.Fail(c, errors.New(errors.ParameterInvalid, "cluster id required"))
	}

	req := &message.OpenUpdateAlertRuleReq{
		ID: clusterID,
	}

	if apiinterceptor.HandleJsonRequestFromBody(c, req) {
		resp, err := regionalservice.GetHandler().UpdateFullPrometheusRule(c, clusterID, req.AlertRules)
		if err != nil {
			apiinterceptor.Fail(c, err)

		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}
}
