package regionalapi

import (
	"net/http"

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

	"github.com/tidbcloud/observability/pkg/regionalapi/apiinterceptor"

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

// CreateCluster
// @Summary create an observability cluster
// @Description  create an observability cluster
// @Tags cluster
// @Accept json
// @Produce json
// @Param request body message.CreateClusterReq true "create request"
// @Success 202 {object} message.Result{data=message.CreateClusterResp}
// @Success 409 {object} message.Result{data=message.CreateClusterResp}
// @Failure 500 {object} message.Result
// @Router /clusters/ [post]
func CreateCluster(c *gin.Context) {
	req := &message.CreateClusterReq{}
	if ok := apiinterceptor.HandleJsonRequestFromBody(c, req); ok {
		resp, err := regionalservice.GetHandler().CreateCluster(c, *req)
		if err != nil {
			if e, ok := err.(errors.Error); ok {
				if e.Code() == errors.DuplicatedCluster {
					apiinterceptor.Succeed(c, http.StatusConflict, resp)
				} else {
					apiinterceptor.Fail(c, err)
				}
			} else {
				apiinterceptor.Fail(c, err)
			}
			return
		}
		apiinterceptor.Succeed(c, http.StatusAccepted, resp)
	}
}

// GetClusterDetail
// @Summary show detail info of a cluster
// @Description show detail info of a cluster
// @Tags cluster
// @Accept json
// @Produce json
// @Param id path string true "cluster id"
// @Param bizType query string false "bizType, for staging, use staging-tidbcloud, others, use tidbcloud"
// @Param request query message.DetailClusterReq true "detail cluster request"
// @Success 200 {object} message.Result{data=message.DetailClusterResp}
// @Failure 404 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /clusters/{id} [get]
func GetClusterDetail(c *gin.Context) {
	req := &message.DetailClusterReq{
		ID:      c.Param("id"),
		BizType: c.GetHeader(string(constants.OpenAPIHeaderBizType)),
	}

	if ok := apiinterceptor.HandleJsonRequestFromQuery(c, req); ok {
		resp, err := regionalservice.GetHandler().GetClusterDetail(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusOK, resp)
		}
	}
}

// DeleteCluster
// @Summary delete a cluster
// @Description delete a cluster
// @Tags cluster
// @Accept json
// @Produce json
// @Param id path string true "cluster id"
// @Param bizType query string false "bizType, for staging, use staging-tidbcloud, others, use tidbcloud"
// @Param request query message.DeleteClusterReq true "delete cluster request"
// @Success 202 {object} message.Result{data=message.DeleteClusterResp}
// @Failure 404 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /clusters/{id} [delete]
func DeleteCluster(c *gin.Context) {
	req := &message.DeleteClusterReq{
		ID:      c.Param("id"),
		BizType: c.GetHeader(string(constants.OpenAPIHeaderBizType)),
	}

	if ok := apiinterceptor.HandleJsonRequestFromQuery(c, req); ok {
		resp, err := regionalservice.GetHandler().DeleteCluster(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}
}

// PauseCluster
// @Summary pause a cluster
// @Description pause a cluster
// @Tags cluster
// @Accept json
// @Produce json
// @Param id path string true "cluster id"
// @Param request query message.PauseClusterReq true "pause cluster request"
// @Success 202 {object} message.Result{data=message.PauseClusterResp}
// @Failure 404 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /clusters/{id}/pause [put]
func PauseCluster(c *gin.Context) {
	req := &message.PauseClusterReq{
		ID: c.Param("id"),
	}

	if ok := apiinterceptor.HandleJsonRequestFromQuery(c, req); ok {
		resp, err := regionalservice.GetHandler().PauseCluster(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}
}

// ResumeCluster
// @Summary resume a cluster
// @Description resume a cluster
// @Tags cluster
// @Accept json
// @Produce json
// @Param id path string true "cluster id"
// @Param request query message.ResumeClusterReq true "resume cluster request"
// @Success 202 {object} message.Result{data=message.ResumeClusterResp}
// @Failure 404 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /clusters/{id}/resume [put]
func ResumeCluster(c *gin.Context) {
	req := &message.ResumeClusterReq{
		ID: c.Param("id"),
	}

	if ok := apiinterceptor.HandleJsonRequestFromQuery(c, req); ok {
		resp, err := regionalservice.GetHandler().ResumeCluster(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}
}

// MuteClusterAlert
// @Summary mute alert of a cluster
// @Description mute alert of a cluster
// @Tags cluster
// @Accept json
// @Produce json
// @Param id path string true "cluster id"
// @Param request query message.MuteClusterAlertReq true "mute cluster alert request"
// @Success 202 {object} message.Result{data=message.MuteClusterAlertResp}
// @Failure 404 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /clusters/{id}/alert/mute [put]
func MuteClusterAlert(c *gin.Context) {
	req := &message.MuteClusterAlertReq{
		ID: c.Param("id"),
	}

	if ok := apiinterceptor.HandleJsonRequestFromBody(c, req); ok {
		resp, err := regionalservice.GetHandler().MuteClusterAlert(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}

}

// UnmuteClusterAlert
// @Summary unmute alert of a cluster
// @Description unmute alert of a cluster
// @Tags cluster
// @Accept json
// @Produce json
// @Param id path string true "cluster id"
// @Param request query message.UnmuteClusterAlertReq true "unmute cluster alert request"
// @Success 202 {object} message.Result{data=message.UnmuteClusterAlertResp}
// @Failure 404 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /clusters/{id}/alert/unmute [put]
func UnmuteClusterAlert(c *gin.Context) {
	req := &message.UnmuteClusterAlertReq{
		ID: c.Param("id"),
	}

	if ok := apiinterceptor.HandleJsonRequestFromBody(c, req); ok {
		resp, err := regionalservice.GetHandler().UnmuteClusterAlert(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}
}

// QueryClusters
// @Summary query clusters
// @Description  query clusters
// @Tags cluster
// @Accept json
// @Produce json
// @Param queryReq query message.QueryClustersReq false "query request"
// @Success 200 {object} message.Result{data=message.QueryClustersWithStorageResp}
// @Failure 500 {object} message.Result
// @Router /clusters/ [get]
func QueryClusters(c *gin.Context) {
	req := &message.QueryClustersReq{}

	if ok := apiinterceptor.HandleJsonRequestFromQuery(c, req); ok {
		resp, err := regionalservice.GetHandler().QueryClustersWithStorage(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusOK, resp)
		}
	}
}

// ModifyMonitorMode
// @Summary adjust spec of monitor share mode
// @Description  adjust spec of monitor share mode
// @Tags cluster
// @Accept json
// @Produce json
// @Param id path string true "cluster id"
// @Param request body message.ModifyMonitorModeReq true "update monitor share mode request"
// @Success 202 {object} message.Result{data=message.ModifyMonitorModeResp}
// @Failure 404 {object} message.Result
// @Failure 405 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /clusters/{id}/monitor-mode/ [put]
func ModifyMonitorMode(c *gin.Context) {
	req := &message.ModifyMonitorModeReq{
		ID: c.Param("id"),
	}

	if ok := apiinterceptor.HandleJsonRequestFromBody(c, req); ok {
		resp, err := regionalservice.GetHandler().MonitorClusterMode(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}
}

// ModifyMonitorSpec
// @Summary adjust spec of monitor spec
// @Description  adjust spec of monitor spec
// @Tags cluster
// @Accept json
// @Produce json
// @Param id path string true "cluster id"
// @Param request body message.ModifyMonitorSpecReq true "update monitor spec request"
// @Success 202 {object} message.Result{data=message.ModifyMonitorSpecResp}
// @Failure 404 {object} message.Result
// @Failure 405 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /clusters/{id}/monitor-spec/ [put]
func ModifyMonitorSpec(c *gin.Context) {
	req := &message.ModifyMonitorSpecReq{
		ID: c.Param("id"),
	}

	if ok := apiinterceptor.HandleJsonRequestFromBody(c, req); ok {
		resp, err := regionalservice.GetHandler().MonitorClusterSpec(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}

}

// ModifyMonitorStorage
// @Summary adjust spec of monitor storage
// @Description  adjust spec of monitor storage
// @Tags cluster
// @Accept json
// @Produce json
// @Param id path string true "cluster id"
// @Param request body message.ModifyMonitorStorageReq true "update monitor storage request"
// @Success 202 {object} message.Result{data=message.ModifyMonitorStorageResp}
// @Failure 404 {object} message.Result
// @Failure 405 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /clusters/{id}/monitor-storage/ [post]
func ModifyMonitorStorage(c *gin.Context) {
	req := &message.ModifyMonitorStorageReq{
		ID: c.Param("id"),
	}

	if ok := apiinterceptor.HandleJsonRequestFromBody(c, req); ok {
		resp, err := regionalservice.GetHandler().ModifyMonitorStorage(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}
}

// ModifyMonitorResource
// @Summary adjust spec of monitor resource
// @Description  adjust spec of monitor resource
// @Tags cluster
// @Accept json
// @Produce json
// @Param id path string true "cluster id"
// @Param request body message.ModifyMonitorResourceReq true "update monitor storage resource"
// @Success 202 {object} message.Result{data=message.ModifyMonitorResourceResp}
// @Failure 404 {object} message.Result
// @Failure 405 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /clusters/{id}/monitor-resource/ [post]
func ModifyMonitorResource(c *gin.Context) {
	req := &message.ModifyMonitorResourceReq{
		ID: c.Param("id"),
	}

	if ok := apiinterceptor.HandleJsonRequestFromBody(c, req); ok {
		resp, err := regionalservice.GetHandler().ModifyMonitorResource(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}
}

// ModifyAgentObserved
// @Summary modify observed info for monitor agent
// @Description  modify observed info for monitor agent
// @Tags cluster
// @Accept json
// @Produce json
// @Param id path string true "cluster id"
// @Param request body message.ModifyAgentObservedReq true "update monitor agent observed info"
// @Success 202 {object} message.Result{data=message.ModifyAgentObservedResp}
// @Failure 404 {object} message.Result
// @Failure 405 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /clusters/{id}/agent-observed/ [post]
func ModifyAgentObserved(c *gin.Context) {
	req := &message.ModifyAgentObservedReq{
		ID: c.Param("id"),
	}

	if ok := apiinterceptor.HandleJsonRequestFromBody(c, req); ok {
		resp, err := regionalservice.GetHandler().ModifyAgentObserved(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}
}

// ModifyAgentObserved
// @Summary modify observed info for monitor agent
// @Description  modify observed info for monitor agent
// @Tags cluster
// @Accept json
// @Produce json
// @Param id path string true "cluster id"
// @Param request body message.ModifyAgentObservedReq true "update monitor agent observed info"
// @Success 202 {object} message.Result{data=message.ModifyAgentObservedResp}
// @Failure 404 {object} message.Result
// @Failure 405 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /clusters/{id}/agent-observed/ [post]
func ModifyAgent(c *gin.Context) {
	req := &message.ModifyAgentObservedReq{
		ID: c.Param("id"),
	}

	if ok := apiinterceptor.HandleJsonRequestFromBody(c, req); ok {
		resp, err := regionalservice.GetHandler().ModifyAgentObserved(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}
}

// UpdateAlertRules
// @Summary update alert rules by cloud user
// @Description update alert rules
// @Tags external
// @Accept json
// @Produce json
// @Param bizType path string true "bizType, for staging, use staging-tidbcloud, others, use tidbcloud"
// @Param tenantID path string true "tenant id"
// @Param projectID path string true "project id"
// @Param applicationID path string true "application id"
// @Param request body message.UpdateAlertRulesByCloudUserReq true "update alert rule request"
// @Success 202 {object} message.Result{data=message.UpdateAlertRulesByCloudUserResp}
// @Failure 404 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /external/{bizType}/orgs/{tenantID}/projects/{projectID}/clusters/{applicationID}/monitor-alertrules [put]
func UpdateAlertRules(c *gin.Context) {
	req := &message.UpdateAlertRulesByCloudUserReq{
		BizType:       c.Param("bizType"),
		TenantID:      c.Param("tenantID"),
		ProjectID:     c.Param("projectID"),
		ApplicationID: c.Param("applicationID"),
	}
	if ok := apiinterceptor.HandleJsonRequestFromBody(c, req); ok {
		resp, err := regionalservice.GetHandler().UpdateAlertRulesByCloudUser(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}
}

// QueryAlertRules
// @Summary query prometheusrules
// @Description query prometheusrules
// @Tags external
// @Accept json
// @Produce json
// @Param bizType path string true "bizType, for staging, use staging-tidbcloud, others, use tidbcloud"
// @Param tenantID path string true "tenant id"
// @Param projectID path string true "project id"
// @Param applicationID path string true "application id"
// @Param request query message.QueryAlertRulesReq true "query prometheusrule request"
// @Success 200 {object} message.Result{data=message.QueryAlertRulesByCloudUserResp}
// @Failure 404 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /external/{bizType}/orgs/{tenantID}/projects/{projectID}/clusters/{applicationID}/monitor-alertrules [get]
func QueryAlertRules(c *gin.Context) {
	req := &message.QueryAlertRulesReq{
		BizType:       c.Param("bizType"),
		TenantID:      c.Param("tenantID"),
		ProjectID:     c.Param("projectID"),
		ApplicationID: c.Param("applicationID"),
	}

	if ok := apiinterceptor.HandleJsonRequestFromQuery(c, req); ok {
		resp, err := regionalservice.GetHandler().QueryAlertRulesByCloudUser(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusOK, resp)
		}
	}
}

// ModifyAlertRulesTemplate
// @Summary modify alertrules template
// @Description modify alertrules template
// @Tags cluster
// @Accept json
// @Produce json
// @Param request query message.ModifyAlertRulesTemplateReq true " modify alertrules template request"
// @Success 200 {object} message.Result{data=message.ModifyAlertRulesTemplateResp}
// @Failure 404 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /alertrule-template/ [post]
func ModifyAlertRulesTemplate(c *gin.Context) {
	req := &message.ModifyAlertRulesTemplateReq{}
	if ok := apiinterceptor.HandleJsonRequestFromBody(c, req); ok {
		resp, err := regionalservice.GetHandler().ModifyAlertRulesTemplate(c, *req)

		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}
}

// DeleteAlertRulesTemplate
// @Summary delete alert rule template
// @Description  delete alert rule template
// @Tags cluster
// @Accept json
// @Produce json
// @Param id path string true "template id"
// @Param request body message.DeleteAlertRulesTemplateReq true "delete alert rule template"
// @Success 202 {object} message.Result{data=message.DeleteAlertRulesTemplateResp}
// @Failure 404 {object} message.Result
// @Failure 405 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /alertrule-template/{id} [delete]
func DeleteAlertRulesTemplate(c *gin.Context) {
	req := &message.DeleteAlertRulesTemplateReq{
		ID: c.Param("id"),
	}
	if ok := apiinterceptor.HandleJsonRequestFromQuery(c, req); ok {
		resp, err := regionalservice.GetHandler().DeleteAlertRulesTemplate(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}
}

// QueryAlertRuleTemplate
// @Summary query alert rule template
// @Description  query alert rule template
// @Tags cluster
// @Accept json
// @Produce json
// @Param id path string true "template id"
// @Param request body message.QueryAlertRulesTemplateReq true "delete alert rule template"
// @Success 202 {object} message.Result{data=message.QueryAlertRulesTemplateResp}
// @Failure 404 {object} message.Result
// @Failure 405 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /alertrule-template/{id} [get]
func QueryAlertRuleTemplate(c *gin.Context) {
	req := &message.QueryAlertRulesTemplateReq{
		ID: c.Param("id"),
	}
	if ok := apiinterceptor.HandleJsonRequestFromQuery(c, req); ok {
		resp, err := regionalservice.GetHandler().QueryAlertRuleTemplate(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusOK, resp)
		}
	}

}

// ApplyLogAlertRules
// @Summary apply log alert rules
// @Description apply log alert rules template
// @Tags cluster
// @Accept json
// @Produce json
// @Param request body message.ApplyLogAlertRulesReq true "apply log alert rules request"
// @Success 202 {object} message.Result{data=message.ModifyAlertRulesTemplateResp}
// @Failure 404 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /alertrule-template/logging/ [post]
func ApplyLogAlertRules(c *gin.Context) {
	req := &message.ApplyLogAlertRulesReq{}
	if ok := apiinterceptor.HandleJsonRequestFromBody(c, req); ok {
		resp, err := regionalservice.GetHandler().ApplyLogAlertRules(c, *req)

		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusAccepted, resp)
		}
	}
}

// UpdateCluster
// @Summary update a cluster
// @Description update a cluster's muteAlert, ruleTemplateID, or monitorSpecID
// @Tags cluster
// @Accept json
// @Produce json
// @Param id path string true "cluster id"
// @Param bizType query string false "bizType, for staging, use staging-tidbcloud, others, use tidbcloud"
// @Param request body message.UpdateClusterReq true "update cluster request"
// @Success 200 {object} message.Result{data=message.UpdateClusterResp}
// @Failure 404 {object} message.Result
// @Failure 409 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /clusters/{id} [put]
func UpdateCluster(c *gin.Context) {
	req := &message.UpdateClusterReq{
		ID: c.Param("id"),
	}

	if ok := apiinterceptor.HandleJsonRequestFromBody(c, req); ok {
		resp, err := regionalservice.GetHandler().UpdateCluster(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusOK, resp)
		}
	}
}

// GetClusterExternal
// @Summary get cluster info for web console
// @Description get cluster info for web console
// @Tags external
// @Accept json
// @Produce json
// @Param bizType path string true "bizType, for staging, use staging-tidbcloud-nextgen, others, use tidbcloud-nextgen"
// @Param tenantID path string true "tenant id"
// @Param applicationID path string true "application id"
// @Success 200 {object} message.Result{data=message.GetClusterExternalResp}
// @Failure 404 {object} message.Result
// @Failure 500 {object} message.Result
// @Router /external/{bizType}/orgs/{tenantID}/clusters/{applicationID}/ [get]
func GetClusterExternal(c *gin.Context) {
	req := &message.GetClusterExternalReq{
		BizType:       c.Param("bizType"),
		TenantID:      c.Param("tenantID"),
		ProjectID:     c.Param("projectID"),
		ApplicationID: c.Param("applicationID"),
	}

	if ok := apiinterceptor.HandleJsonRequestFromQuery(c, req); ok {
		resp, err := regionalservice.GetHandler().GetClusterExternal(c, *req)
		if err != nil {
			apiinterceptor.Fail(c, err)
		} else {
			apiinterceptor.Succeed(c, http.StatusOK, resp)
		}
	}
}
