package cluster

import (
	"fmt"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/devops/api"
	clusterapi "github.com/tidbcloud/devops/api/cluster"
	ctrl "github.com/tidbcloud/devops/pkg/controller"
	cmxapi "github.com/tidbcloud/devops/pkg/service/clustermaintenance/api"
)

// ListClusterOpsMaintenanceWindows
//
//	@Id				ClusterServiceListClusterOpsMaintenanceWindows
//	@Description	list cluster ops maintenance windows
//	@Tags			ClusterService
//	@Accept			json
//	@Produce		json
//	@Param			req	query		clusterapi.ListClusterOpsMaintenanceWindowsReq	false	"request param"
//	@Success		200	{object}	clusterapi.ListClusterOpsMaintenanceWindowsResp
//	@Router			/api/v1/devops/cluster/ops-maintenance-windows [get]
func (c *ClusterController) ListClusterOpsMaintenanceWindows(ctx *gin.Context) {
	req := &clusterapi.ListClusterOpsMaintenanceWindowsReq{}
	err := ctx.ShouldBindQuery(req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}

	items, total, err := c.maintenanceSvc.ListClusterOpsMaintenanceWindows(ctx, cmxapi.ListClusterOpsMaintenanceWindowParam{
		ClusterIDs: req.ClusterIDs,
		Page:       int64(req.Page),
		PerPage:    int64(req.PerPage),
	})
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}

	ctrl.Success(ctx, &clusterapi.ListClusterOpsMaintenanceWindowsResp{
		Items: items,
		Total: total,
	})
}

// GetClusterOpsMaintenanceWindow
//
//	@Id				ClusterServiceGetClusterOpsMaintenanceWindow
//	@Description	get a cluster ops maintenance window by cluster id
//	@Tags			ClusterService
//	@Accept			json
//	@Produce		json
//	@Param			cluster_id	path		string	true	"cluster id"
//	@Success		200			{object}	clusterapi.GetClusterOpsMaintenanceWindowResp
//	@Router			/api/v1/devops/cluster/ops-maintenance-windows/{cluster_id} [get]
func (c *ClusterController) GetClusterOpsMaintenanceWindow(ctx *gin.Context) {
	clusterID := ctx.Param("cluster_id")
	if clusterID == "" {
		ctrl.FailWithCode(ctx, fmt.Errorf("cluster id is required"), api.ErrCodeInvalidArgument)
		return
	}

	item, err := c.maintenanceSvc.GetClusterOpsMaintenanceWindow(ctx, clusterID)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}

	ctrl.Success(ctx, &clusterapi.GetClusterOpsMaintenanceWindowResp{
		Item: item,
	})
}

// CreateClusterOpsMaintenanceWindow
//
//	@Id				ClusterServiceCreateClusterOpsMaintenanceWindow
//	@Description	create a cluster ops maintenance window
//	@Tags			ClusterService
//	@Accept			json
//	@Produce		json
//	@Param			req	body		clusterapi.CreateClusterOpsMaintenanceWindowReq	true	"request param"
//	@Success		200	{object}	clusterapi.CreateClusterOpsMaintenanceWindowResp
//	@Router			/api/v1/devops/cluster/ops-maintenance-windows [post]
func (c *ClusterController) CreateClusterOpsMaintenanceWindow(ctx *gin.Context) {
	req := &clusterapi.CreateClusterOpsMaintenanceWindowReq{}
	err := ctx.ShouldBindJSON(req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}

	item, err := c.maintenanceSvc.CreateClusterOpsMaintenanceWindow(ctx, cmxapi.CreateClusterOpsMaintenanceWindowParam{
		ClusterID: req.ClusterID,
		Windows:   req.Windows,
		Approvers: req.Approvers,
	})
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}

	ctrl.Success(ctx, &clusterapi.CreateClusterOpsMaintenanceWindowResp{
		Item: item,
	})
}

// UpdateClusterOpsMaintenanceWindow
//
//	@Id				ClusterServiceUpdateClusterOpsMaintenanceWindow
//	@Description	update a cluster ops maintenance window
//	@Tags			ClusterService
//	@Accept			json
//	@Produce		json
//	@Param			cluster_id	path		string											true	"cluster id"
//	@Param			req			body		clusterapi.UpdateClusterOpsMaintenanceWindowReq	true	"request param"
//	@Success		200			{object}	clusterapi.UpdateClusterOpsMaintenanceWindowResp
//	@Router			/api/v1/devops/cluster/ops-maintenance-windows/{cluster_id} [put]
func (c *ClusterController) UpdateClusterOpsMaintenanceWindow(ctx *gin.Context) {
	clusterID := ctx.Param("cluster_id")
	if clusterID == "" {
		ctrl.FailWithCode(ctx, fmt.Errorf("cluster id is required"), api.ErrCodeInvalidArgument)
		return
	}

	req := &clusterapi.UpdateClusterOpsMaintenanceWindowReq{}
	err := ctx.ShouldBindJSON(req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}

	item, err := c.maintenanceSvc.UpdateClusterOpsMaintenanceWindow(ctx, clusterID, cmxapi.UpdateClusterOpsMaintenanceWindowParam{
		Windows:   req.Windows,
		Approvers: req.Approvers,
	})
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}

	ctrl.Success(ctx, &clusterapi.UpdateClusterOpsMaintenanceWindowResp{
		Item: item,
	})
}

// DeleteClusterOpsMaintenanceWindow
//
//	@Id				ClusterServiceDeleteClusterOpsMaintenanceWindow
//	@Description	delete a cluster ops maintenance window
//	@Tags			ClusterService
//	@Accept			json
//	@Produce		json
//	@Param			cluster_id	path		string	true	"cluster id"
//	@Success		200			{object}	api.BaseResp
//	@Router			/api/v1/devops/cluster/ops-maintenance-windows/{cluster_id} [delete]
func (c *ClusterController) DeleteClusterOpsMaintenanceWindow(ctx *gin.Context) {
	clusterID := ctx.Param("cluster_id")
	if clusterID == "" {
		ctrl.FailWithCode(ctx, fmt.Errorf("cluster id is required"), api.ErrCodeInvalidArgument)
		return
	}

	err := c.maintenanceSvc.DeleteClusterOpsMaintenanceWindow(ctx, clusterID)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}

	ctrl.Success(ctx, nil)
}

// IsInClusterOpsMaintenanceWindow
//
//	@Id				ClusterServiceIsInClusterOpsMaintenanceWindow
//	@Description	get a cluster ops maintenance window by cluster id
//	@Tags			ClusterService
//	@Accept			json
//	@Produce		json
//	@Param			cluster_id	path		string											true	"cluster id"
//	@Param			req			query		clusterapi.IsInClusterOpsMaintenanceWindowReq	false	"request param"
//	@Success		200			{object}	clusterapi.IsInClusterOpsMaintenanceWindowResp
//	@Router			/api/v1/devops/cluster/ops-maintenance-windows/{cluster_id}/check [get]
func (c *ClusterController) IsInClusterOpsMaintenanceWindow(ctx *gin.Context) {
	clusterID := ctx.Param("cluster_id")
	if clusterID == "" {
		ctrl.FailWithCode(ctx, fmt.Errorf("cluster id is required"), api.ErrCodeInvalidArgument)
		return
	}

	req := &clusterapi.IsInClusterOpsMaintenanceWindowReq{}
	if err := ctx.ShouldBindQuery(req); err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}

	var executeTimes []time.Time
	for _, rawExecuteTime := range req.ExecuteTimes {
		executeTimes = append(executeTimes, time.Unix(rawExecuteTime, 0))
	}

	is, item, err := c.maintenanceSvc.IsInClusterOpsMaintenanceWindow(ctx, clusterID, executeTimes)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}

	ctrl.Success(ctx, &clusterapi.IsInClusterOpsMaintenanceWindowResp{
		Is:   is,
		Item: item,
	})
}
