package cloudconfig

import (
	"context"
	"fmt"

	"github.com/tidbcloud/config-center/proto/config_center"
	"github.com/tidbcloud/devops/api"
	ccapi "github.com/tidbcloud/devops/api/cloudconfig"
	_ "github.com/tidbcloud/devops/entity/cloudconfig"
	ctrl "github.com/tidbcloud/devops/pkg/controller"
	"github.com/tidbcloud/devops/pkg/infra/consts"
	ccsvcapi "github.com/tidbcloud/devops/pkg/service/cloudconfig/api"

	"github.com/gin-gonic/gin"
)

// ListParameterVersions
//
//	@Id				CloudConfigControllerListParameterVersions
//	@Description	list available versions from dict
//	@Tags			CloudConfigController
//	@Accept			json
//	@Produce		json
//	@Param			cluster_type	query		cloudconfig.ClusterType	true	"cluster_type"
//	@Success		200				{object}	ccapi.ListParamVersionsResp
//	@Router			/api/v1/devops/cloudconfig/parameter/versions [get]
func (c *CloudConfigController) ListParameterVersions(ctx *gin.Context) {

	versionResp, err := c.cfgCenter.ConfigAPI.ListConfigurationDictVersions(context.Background(), &config_center.ListConfigurationDictVersionsRequest{
		ClusterType: config_center.ClusterType(config_center.ClusterType_value[ctx.Query("cluster_type")]),
	})
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}

	resp := &ccapi.ListParamVersionsResp{
		Versions: versionResp.Versions,
	}

	ctrl.Success(ctx, resp)
}

// ListParameterAttributes
//
//	@Id				CloudConfigControllerListParameterAttributes
//	@Description	list parameter attributes
//	@Tags			CloudConfigController
//	@Accept			json
//	@Produce		json
//	@Param			cluster_type	query		cloudconfig.ClusterType	true	"cluster_type"
//	@Param			configtype		path		string					true	"configtype"
//	@Param			version			path		string					true	"version"
//	@Param			req				query		ccapi.ListParamAttrReq	false	"request param"
//	@Success		200				{object}	ccapi.ListParamAttrResp
//	@Router			/api/v1/devops/cloudconfig/parameter/attribute/{configtype}/{version} [get]
func (c *CloudConfigController) ListParameterAttributes(ctx *gin.Context) {
	configType := ctx.Param("configtype")
	version := ctx.Param("version")
	if configType == "" || version == "" {
		ctrl.FailWithCode(ctx, fmt.Errorf("configtype and version are required"), api.ErrCodeInvalidArgument)
		return
	}
	clusterType := ctx.Query("cluster_type")

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

	param := ccsvcapi.ListParamAttributesParam{
		ClusterType: clusterType,
		ConfigType:  configType,
		VersionIs:   &version,
		NameLike:    req.NameLike,
		NameIn:      req.NameIn,
		Page:        int64(req.Page),
		PerPage:     int64(req.PerPage),
	}
	attrs, total, err := c.svc.ListParameterAttribute(ctx, param)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}

	resp := &ccapi.ListParamAttrResp{
		Attributes: attrs,
		Total:      total,
	}
	ctrl.Success(ctx, resp)
}

// GetParameterAttribute
//
//	@Id				CloudConfigControllerGetParameterAttribute
//	@Description	get a parameter attribute
//	@Tags			CloudConfigController
//	@Accept			json
//	@Produce		json
//	@Param			cluster_type	query		cloudconfig.ClusterType	true	"cluster_type"
//	@Param			configtype		path		string					true	"configtype"
//	@Param			version			path		string					true	"version"
//	@Param			param_name		path		string					true	"param_name"
//	@Success		200				{object}	ccapi.GetParamAttrResp
//	@Router			/api/v1/devops/cloudconfig/parameter/attribute/{configtype}/{version}/{param_name} [get]
func (c *CloudConfigController) GetParameterAttribute(ctx *gin.Context) {
	configType := ctx.Param("configtype")
	version := ctx.Param("version")
	name := ctx.Param("param_name")
	clusterType := ctx.Query("cluster_type")
	if configType == "" || version == "" || name == "" {
		ctrl.FailWithCode(ctx, fmt.Errorf("configtype, version and name are required"), api.ErrCodeInvalidArgument)
		return
	}

	attr, err := c.svc.GetParameterAttribute(ctx, clusterType, configType, version, name)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}

	resp := &ccapi.GetParamAttrResp{Attribute: attr}
	ctrl.Success(ctx, resp)
}

// UpdateParameterAttribute
//
//	@Id				CloudConfigControllerUpdateParameterAttribute
//	@Description	update a parameter attribute
//	@Tags			CloudConfigController
//	@Accept			json
//	@Produce		json
//	@Param			cluster_type	query		cloudconfig.ClusterType		true	"cluster_type"
//	@Param			config_type		path		string						true	"config_type"
//	@Param			version			path		string						true	"version"
//	@Param			param_name		path		string						true	"param_name"
//	@Param			req				body		ccapi.UpdateParamAttrReq	true	"request param"
//	@Success		200				{object}	api.BaseResp
//	@Router			/api/v1/devops/cloudconfig-admin/parameter/attribute/{config_type}/{version}/{param_name} [put]
func (c *CloudConfigController) UpdateParameterAttribute(ctx *gin.Context) {
	clusterType := ctx.Query("cluster_type")
	configType := ctx.Param("config_type")
	version := ctx.Param("version")
	name := ctx.Param("param_name")
	if configType == "" || version == "" || name == "" {
		ctrl.FailWithCode(ctx, fmt.Errorf("filename, version and name are required"), api.ErrCodeInvalidArgument)
		return
	}

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

	param := ccsvcapi.UpdateParamterAttributeParam{
		ApplyPolicy:  req.ApplyPolicy,
		DefaultValue: req.DefaultValue,
		Validation:   req.Validation,
		Description:  req.Description,
		RiskLevel:    req.RiskLevel,
		UpdatedBy:    ctx.GetString(consts.CtxUserEmail),
	}
	if req.UpdatedBy != nil && *req.UpdatedBy != "" {
		param.UpdatedBy = *req.UpdatedBy
	}
	err = c.svc.UpdateParameterAttribute(ctx, clusterType, configType, version, name, param)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}

	ctrl.Success(ctx, nil)
}

// CreateParameterAttribute
//
//	@Id				CloudConfigControllerCreateParameterAttribute
//	@Description	create a paramter attribute
//	@Tags			CloudConfigController
//	@Accept			json
//	@Produce		json
//	@Param			req	body		ccapi.CreateParamAttrReq	true	"request param"
//	@Success		200	{object}	api.BaseResp
//	@Router			/api/v1/devops/cloudconfig-admin/parameter/attribute/create [post]
func (c *CloudConfigController) CreateParameterAttribute(ctx *gin.Context) {
	req := &ccapi.CreateParamAttrReq{}
	err := ctx.ShouldBindJSON(req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}

	err = c.svc.CreateParameterAttribute(ctx, *req.Attribute)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}

	ctrl.Success(ctx, nil)
}

// CloneParameterAttribute
//
//	@Id				CloudConfigControllerCloneParameterAttribute
//	@Description	clone paramter attributes from old version
//	@Tags			CloudConfigController
//	@Accept			json
//	@Produce		json
//	@Param			req	body		ccapi.CloneParamAttrReq	true	"request param"
//	@Success		200	{object}	api.BaseResp
//	@Router			/api/v1/devops/cloudconfig-admin/parameter/attribute/clone [post]
func (c *CloudConfigController) CloneParameterAttribute(ctx *gin.Context) {
	req := &ccapi.CloneParamAttrReq{}
	err := ctx.ShouldBindJSON(req)
	if err != nil {
		ctrl.FailWithCode(ctx, err, api.ErrCodeInvalidArgument)
		return
	}

	err = c.svc.CloneParameterAttributes(ctx, req.FromVersion, req.ToVersion)
	if err != nil {
		ctrl.Fail(ctx, err)
		return
	}

	ctrl.Success(ctx, nil)
}
