package configcenter

import (
	"fmt"

	"go.uber.org/dig"

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/devops/api"
	configcenterapi "github.com/tidbcloud/devops/api/configcenter"
	"github.com/tidbcloud/devops/entity"
	ctrl "github.com/tidbcloud/devops/pkg/controller"
	"github.com/tidbcloud/devops/pkg/infra/log"
	"github.com/tidbcloud/devops/pkg/service/configcenter"
)

type ControllerParam struct {
	dig.In

	ConfigCenterService configcenter.ConfigCenterServiceAPI
}

type ConfigCenterController struct {
	cfgctSvc configcenter.ConfigCenterServiceAPI
}

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

func NewConfigCenterController(p ControllerParam) ctrl.Controller {
	return &ConfigCenterController{
		cfgctSvc: p.ConfigCenterService,
	}
}

func (c *ConfigCenterController) RegisterAPI(suite *ctrl.Suite) error {
	r := suite.Router
	group := r.Group("/configcenter")

	{
		group.GET("/list", c.List)
		group.POST("/add", c.Add)
		group.POST("copy", c.Copy)
		group.POST("modify", c.Modify)
	}

	return nil
}

// ListConfigAttribute
//
//	@Id				ListConfigAttribute
//	@Description	List Config Attribute in Some Version
//	@Tags			ConfigCenterService
//	@Accept			json
//	@Produce		json
//	@Param			req	query		configcenterapi.ListAttributesReq	true	"request param"
//	@Success		200	{object}	configcenterapi.ListAttributesResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/configcenter/list [get]
func (c *ConfigCenterController) List(ctx *gin.Context) {
	req := &configcenterapi.ListAttributesReq{}
	err := ctx.ShouldBindQuery(req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}

	if req.ParamName == `` && req.Version == `` {
		ctrl.FailWithCode(ctx, fmt.Errorf("either param name or version is needed"), api.ErrCodeInternal)
		return
	}
	param := configcenter.ListAttributesReq{
		ParamName: req.ParamName,
		Version:   req.Version,
		Component: req.Component,
	}
	attributes, err := c.cfgctSvc.ListAttributes(ctx, param)
	if err != nil {
		ctrl.FailWithCode(ctx, fmt.Errorf("internal list attributes error: %s", err), api.ErrCodeInternal)
		return
	}
	resp := &configcenterapi.ListAttributesResp{Attributes: attributes}
	ctrl.Success(ctx, resp)
}

// AddConfigAttribute
//
//	@Id				AddConfigAttribute
//	@Description	Add Config Attribute for Some Version
//	@Tags			ConfigCenterService
//	@Accept			json
//	@Produce		json
//	@Param			req	body		configcenterapi.AddAttributeReq	true	"request param"
//	@Success		200	{object}	api.BaseResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/configcenter/add [post]
func (c *ConfigCenterController) Add(ctx *gin.Context) {
	req := &configcenterapi.AddAttributeReq{}
	err := ctx.ShouldBindJSON(req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}

	err = c.cfgctSvc.AddAttribute(ctx, configcenter.AddAttributeReq(*req))
	if err != nil {
		ctrl.FailWithCode(ctx, fmt.Errorf("internal add attribute error: %s", err), api.ErrCodeInternal)
		return
	}
	ctrl.Success(ctx, nil)
}

// CopyAttributeFromVersion
//
//	@Id				CopyAttributeFromVersion
//	@Description	Copy All Config Attribute From Some Version
//	@Tags			ConfigCenterService
//	@Accept			json
//	@Produce		json
//	@Param			req	body		configcenterapi.CopyFromVersionReq	true	"request param"
//	@Success		200	{object}	api.BaseResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/configcenter/copy [post]
func (c *ConfigCenterController) Copy(ctx *gin.Context) {
	req := &configcenterapi.CopyFromVersionReq{}
	err := ctx.ShouldBindJSON(req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}
	param := configcenter.CopyFromVersionReq{FromVersion: req.FromVersion, ToVersion: req.ToVersion}
	log.Logger.Info("controller copy param", "from version", req.FromVersion, "to version", req.ToVersion)
	err = c.cfgctSvc.CopyFromVersion(ctx, param)
	if err != nil {
		ctrl.FailWithCode(ctx, fmt.Errorf("internal copy atrribute error: %s", err), api.ErrCodeInternal)
		return
	}
	ctrl.Success(ctx, nil)
}

// ModifyAttribute
//
//	@Id				ModifyAttribute
//	@Description	Modify some attribute
//	@Tags			ConfigCenterService
//	@Accept			json
//	@Produce		json
//	@Param			req	body		configcenterapi.ModifyReq	true	"request param"
//	@Success		200	{object}	api.BaseResp
//	@Failure		500	{object}	api.BaseResp
//	@Router			/api/v1/devops/configcenter/modify [post]
func (c *ConfigCenterController) Modify(ctx *gin.Context) {
	req := &configcenterapi.ModifyReq{}
	err := ctx.ShouldBindJSON(req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}
	err = c.cfgctSvc.Modify(ctx, configcenter.ModifyReq{ConfigAttribute: (*entity.ConfigAttributes)(req)})
	if err != nil {
		ctrl.FailWithCode(ctx, fmt.Errorf("internal modify atrribute error: %s", err), api.ErrCodeInternal)
		return
	}
	ctrl.Success(ctx, nil)
}
