package dashboard

import (
	"fmt"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/devops/api"
	dashboardapi "github.com/tidbcloud/devops/api/dashboard"
	"github.com/tidbcloud/devops/entity"
	ctrl "github.com/tidbcloud/devops/pkg/controller"
	"github.com/tidbcloud/devops/pkg/service/dashboard"
	"go.uber.org/dig"
)

type ControllerParam struct {
	dig.In

	DashboardService dashboard.DashboardServiceAPI
}

type DashboardController struct {
	dashboardService dashboard.DashboardServiceAPI
}

func (c *DashboardController) Name() string {
	return "DashboardController"
}

func NewDashboardController(p ControllerParam) ctrl.Controller {
	return &DashboardController{
		dashboardService: p.DashboardService,
	}
}

func (c *DashboardController) RegisterAPI(suite *ctrl.Suite) error {
	r := suite.Router
	group := r.Group("/dashboard")
	{
		group.GET("/sla", c.GetSLAInfo)
		group.GET("/sla-dedicated-monthly", c.GetMonthlySummaryOfDedicatedSLA)
		group.GET("/sla-dedicated-detail", c.GetClusterDetailOfDedicatedSLA)
		group.GET("/sla-next-gen-monthly", c.GetMonthlySummaryOfNextGenSLA)
		group.GET("/sla-next-gen-detail", c.GetClusterDetailOfNextGenSLA)
		group.GET("/slo", c.GetSLOInfo)

		group.GET("/incident", c.GetIncidentInfo)
		group.GET("/cloud-oncall", c.GetCloudOncallInfo)
		group.GET("/critical-alert", c.GetCriticalAlertInfo)
		group.GET("/release", c.GetReleaseInfo)

		group.GET("/top-qps-tenants", c.GetTop10QPSTenants)
		group.GET("/top-tikv-storage-tenants", c.GetTop10TiKVStorageTenants)
		group.GET("/top-tiflash-storage-tenants", c.GetTop10TiFlashStorageTenants)
	}
	return nil
}

// GetSLAInfo
//
//	@Id				GetSLAInfo
//	@Description	get sla info
//	@Tags			DashboardService
//	@Accept			json
//	@Produce		json
//	@Param			req	query		dashboardapi.DashboardReq	true	"DashboardReq"
//	@Success		200	{object}	dashboardapi.SLAInfoResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/dashboard/sla [get]
func (c *DashboardController) GetSLAInfo(ctx *gin.Context) {
	req := dashboardapi.DashboardReq{}
	err := ctx.ShouldBindQuery(&req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}
	result, err := c.dashboardService.GetSLAInfo(ctx, req.StartTs, req.EndTs)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}
	resp := dashboardapi.SLAInfoResp{SLAInfo: *result}
	ctrl.Success(ctx, resp)
}

// GetMonthlySummaryOfDedicatedSLA
//
//	@Id				GetMonthlySummaryOfDedicatedSLA
//	@Description	get monthly summary of dedicated sla
//	@Tags			DashboardService
//	@Accept			json
//	@Produce		json
//	@Param			req	query		dashboardapi.GetMonthlySummaryOfDedicatedSLAReq	true	"GetMonthlySummaryOfDedicatedSLAReq"
//	@Success		200	{object}	dashboardapi.GetMonthlySummaryOfDedicatedSLAResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/dashboard/sla-dedicated-monthly [get]
func (c *DashboardController) GetMonthlySummaryOfDedicatedSLA(ctx *gin.Context) {
	req := dashboardapi.GetMonthlySummaryOfDedicatedSLAReq{}
	err := ctx.ShouldBindQuery(&req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}
	if _, err := time.Parse("2006/1", req.Month); err != nil {
		ctrl.FailWithCode(ctx, fmt.Errorf("invalid month format"), api.ErrCodeInvalidArgument)
		return
	}
	result, err := c.dashboardService.GetMonthlySummaryOfDedicatedSLA(ctx,
		req.Month, entity.DedicatedSLAFilter{
			Search:           req.Search,
			IncludeDeleted:   req.IncludeDeleted,
			Status:           req.Status,
			TiDBInstanceMode: entity.TiDBInstanceMode(req.TiDBInstanceMode),
		})
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}
	resp := dashboardapi.GetMonthlySummaryOfDedicatedSLAResp{DedicatedClusterSLABasicList: *result}
	ctrl.Success(ctx, resp)
}

// GetMonthlySummaryOfNextGenSLA
//
//	@Id				GetMonthlySummaryOfNextGenSLA
//	@Description	get monthly summary of next-gen sla
//	@Tags			DashboardService
//	@Accept			json
//	@Produce		json
//	@Param			req	query		dashboardapi.GetMonthlySummaryOfNextGenSLAReq	true	"GetMonthlySummaryOfNextGenSLAReq"
//	@Success		200	{object}	dashboardapi.GetMonthlySummaryOfNextGenSLAResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/dashboard/sla-next-gen-monthly [get]
func (c *DashboardController) GetMonthlySummaryOfNextGenSLA(ctx *gin.Context) {
	req := dashboardapi.GetMonthlySummaryOfNextGenSLAReq{}
	err := ctx.ShouldBindQuery(&req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}
	if _, err := time.Parse("2006/1", req.Month); err != nil {
		ctrl.FailWithCode(ctx, fmt.Errorf("invalid month format"), api.ErrCodeInvalidArgument)
		return
	}
	result, err := c.dashboardService.GetMonthlySummaryOfNextGenSLA(ctx,
		req.Month, entity.NextGenSLAFilter{
			Search:            req.Search,
			IncludeDeleted:    req.IncludeDeleted,
			Status:            req.Status,
			ClusterDeployType: req.ClusterDeployType,
		})
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}
	resp := dashboardapi.GetMonthlySummaryOfNextGenSLAResp{NextGenClusterSLABasicList: *result}
	ctrl.Success(ctx, resp)
}

// GetClusterDetailOfDedicatedSLA
//
//	@Id				GetClusterDetailOfDedicatedSLA
//	@Description	get cluster detail of dedicated sla
//	@Tags			DashboardService
//	@Accept			json
//	@Produce		json
//	@Param			req	query		dashboardapi.GetClusterDetailOfDedicatedSLAReq	true	"GetClusterDetailOfDedicatedSLAReq"
//	@Success		200	{object}	dashboardapi.GetClusterDetailOfDedicatedSLAResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/dashboard/sla-dedicated-detail [get]
func (c *DashboardController) GetClusterDetailOfDedicatedSLA(ctx *gin.Context) {
	req := dashboardapi.GetClusterDetailOfDedicatedSLAReq{}
	err := ctx.ShouldBindQuery(&req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}
	if _, err := time.Parse("2006/1", req.Month); err != nil {
		ctrl.FailWithCode(ctx, fmt.Errorf("invalid month format"), api.ErrCodeInvalidArgument)
		return
	}
	result, err := c.dashboardService.GetClusterDetailOfDedicatedSLA(ctx,
		req.Month, req.ClusterID, req.IncludeFake)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}
	resp := dashboardapi.GetClusterDetailOfDedicatedSLAResp{DedicatedClusterSLADetail: *result}
	ctrl.Success(ctx, resp)
}

// GetClusterDetailOfNextGenSLA
//
//	@Id				GetClusterDetailOfNextGenSLA
//	@Description	get cluster detail of next-gen sla
//	@Tags			DashboardService
//	@Accept			json
//	@Produce		json
//	@Param			req	query		dashboardapi.GetClusterDetailOfNextGenSLAReq	true	"GetClusterDetailOfNextGenSLAReq"
//	@Success		200	{object}	dashboardapi.GetClusterDetailOfNextGenSLAResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/dashboard/sla-next-gen-detail [get]
func (c *DashboardController) GetClusterDetailOfNextGenSLA(ctx *gin.Context) {
	req := dashboardapi.GetClusterDetailOfNextGenSLAReq{}
	err := ctx.ShouldBindQuery(&req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}
	if _, err := time.Parse("2006/1", req.Month); err != nil {
		ctrl.FailWithCode(ctx, fmt.Errorf("invalid month format"), api.ErrCodeInvalidArgument)
		return
	}
	result, err := c.dashboardService.GetClusterDetailOfNextGenSLA(ctx,
		req.Month, req.ClusterID, req.IncludeFake)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}
	resp := dashboardapi.GetClusterDetailOfNextGenSLAResp{NextGenClusterSLADetail: *result}
	ctrl.Success(ctx, resp)
}

// GetSLOInfo
//
//	@Id				GetSLOInfo
//	@Description	get slo info
//	@Tags			DashboardService
//	@Accept			json
//	@Produce		json
//	@Success		200	{object}	dashboardapi.SLOInfoResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/dashboard/slo [get]
func (c *DashboardController) GetSLOInfo(ctx *gin.Context) {
	result, err := c.dashboardService.GetSLOInfo(ctx)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}
	resp := dashboardapi.SLOInfoResp{SLOInfo: *result}
	ctrl.Success(ctx, resp)
}

// GetIncidentInfo
//
//	@Id				GetIncidentInfo
//	@Description	get incident info
//	@Tags			DashboardService
//	@Accept			json
//	@Produce		json
//	@Param			req	query		dashboardapi.DashboardReq	true	"DashboardReq"
//	@Success		200	{object}	dashboardapi.IncidentInfoResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/dashboard/incident [get]
func (c *DashboardController) GetIncidentInfo(ctx *gin.Context) {
	req := dashboardapi.DashboardReq{}
	err := ctx.ShouldBindQuery(&req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}
	result, err := c.dashboardService.GetIncidentInfo(ctx, req.StartTs, req.EndTs)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}
	resp := dashboardapi.IncidentInfoResp{IncidentInfo: *result}
	ctrl.Success(ctx, resp)
}

// GetCloudOncallInfo
//
//	@Id				GetCloudOncallInfo
//	@Description	get cloud oncall info
//	@Tags			DashboardService
//	@Accept			json
//	@Produce		json
//	@Param			req	query		dashboardapi.DashboardReq	true	"DashboardReq"
//	@Success		200	{object}	dashboardapi.CloudOncallInfoResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/dashboard/cloud-oncall [get]
func (c *DashboardController) GetCloudOncallInfo(ctx *gin.Context) {
	req := dashboardapi.DashboardReq{}
	err := ctx.ShouldBindQuery(&req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}
	result, err := c.dashboardService.GetCloudOncallInfo(ctx, req.StartTs, req.EndTs)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}
	resp := dashboardapi.CloudOncallInfoResp{CloudOncallInfo: *result}
	ctrl.Success(ctx, resp)
}

// GetCriticalAlertInfo
//
//	@Id				GetCriticalAlertInfo
//	@Description	get critical alert info
//	@Tags			DashboardService
//	@Accept			json
//	@Produce		json
//	@Param			req	query		dashboardapi.DashboardReq	true	"DashboardReq"
//	@Success		200	{object}	dashboardapi.CriticalAlertInfoResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/dashboard/critical-alert [get]
func (c *DashboardController) GetCriticalAlertInfo(ctx *gin.Context) {
	req := dashboardapi.DashboardReq{}
	err := ctx.ShouldBindQuery(&req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}
	result, err := c.dashboardService.GetAlertInfo(ctx, req.StartTs, req.EndTs)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}
	resp := dashboardapi.CriticalAlertInfoResp{CriticalAlertInfo: *result}
	ctrl.Success(ctx, resp)
}

// GetReleaseInfo
//
//	@Id				GetReleaseInfo
//	@Description	get release info
//	@Tags			DashboardService
//	@Accept			json
//	@Produce		json
//	@Param			req	query		dashboardapi.DashboardReq	true	"DashboardReq"
//	@Success		200	{object}	dashboardapi.ReleaseInfoResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/dashboard/release [get]
func (c *DashboardController) GetReleaseInfo(ctx *gin.Context) {
	req := dashboardapi.DashboardReq{}
	err := ctx.ShouldBindQuery(&req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}
	result, err := c.dashboardService.GetReleaseInfo(ctx, req.StartTs, req.EndTs)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}
	resp := dashboardapi.ReleaseInfoResp{ReleaseInfo: *result}
	ctrl.Success(ctx, resp)
}

// GetTop10QPSTenants
//
//	@Id				GetTop10QPSTenants
//	@Description	get top10 qps tenants
//	@Tags			DashboardService
//	@Accept			json
//	@Produce		json
//	@Success		200	{object}	dashboardapi.GetTop10QPSTenantsResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/dashboard/top-qps-tenants [get]
func (c *DashboardController) GetTop10QPSTenants(ctx *gin.Context) {
	result, err := c.dashboardService.GetTop10QPSTenants(ctx)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}
	resp := dashboardapi.GetTop10QPSTenantsResp{TopTenants: *result}
	ctrl.Success(ctx, resp)
}

// GetTop10TiKVStorageTenants
//
//	@Id				GetTop10TiKVStorageTenants
//	@Description	get top10 tikv storage tenants
//	@Tags			DashboardService
//	@Accept			json
//	@Produce		json
//	@Success		200	{object}	dashboardapi.GetTop10TiKVStorageTenantsResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/dashboard/top-tikv-storage-tenants [get]
func (c *DashboardController) GetTop10TiKVStorageTenants(ctx *gin.Context) {
	result, err := c.dashboardService.GetTop10TiKVStorageTenants(ctx)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}
	resp := dashboardapi.GetTop10TiKVStorageTenantsResp{TopTenants: *result}
	ctrl.Success(ctx, resp)
}

// GetTop10TiFlashStorageTenants
//
//	@Id				GetTop10TiFlashStorageTenants
//	@Description	get top10 tiflash storage tenants
//	@Tags			DashboardService
//	@Accept			json
//	@Produce		json
//	@Success		200	{object}	dashboardapi.GetTop10TiFlashStorageTenantsResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/dashboard/top-tiflash-storage-tenants [get]
func (c *DashboardController) GetTop10TiFlashStorageTenants(ctx *gin.Context) {
	result, err := c.dashboardService.GetTop10TiFlashStorageTenants(ctx)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}
	resp := dashboardapi.GetTop10TiFlashStorageTenantsResp{TopTenants: *result}
	ctrl.Success(ctx, resp)
}
