package ngoperation

import (
	"context"
	"fmt"

	commonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	mgmtv1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"

	opent "github.com/tidbcloud/devops/entity/operation"
	"github.com/tidbcloud/devops/pkg/service/operation/actions"
)

var (
	ActionSetDefaultResourcePool = opent.ActionMetadata{
		Name: "SetDefaultResourcePool",
		Type: opent.ActionTypeAuto,
	}
)

var (
	_ actions.Action = &SetDefaultResourcePool{}
)

type SetDefaultResourcePool struct {
	actions.BaseAction
	comps *actions.Components
}

func NewSetDefaultResourcePool(comps *actions.Components) actions.AutoAction {
	return &SetDefaultResourcePool{comps: comps}
}

func (a *SetDefaultResourcePool) Metadata() opent.ActionMetadata {
	return ActionSetDefaultResourcePool
}

func (a *SetDefaultResourcePool) PreCheck(ctx context.Context, instance *opent.Instance) error {
	req, err := a.getParam(instance)
	if err != nil {
		return err
	}
	if err := validateSetDefaultResourcePoolServicePlan(ctx, a.comps.CoreSvc.Mgmt, req.GetDefaultResourcePoolId(), req.GetOrganizationId(), "setting default resource pool"); err != nil {
		return err
	}

	return nil
}

func (a *SetDefaultResourcePool) Start(ctx context.Context, instance *opent.Instance) (*actions.ActionResult, error) {

	req, err := a.getParam(instance)
	if err != nil {
		return actions.FailedActionResult(err), nil
	}
	if err := validateSetDefaultResourcePoolServicePlan(ctx, a.comps.CoreSvc.Mgmt, req.GetDefaultResourcePoolId(), req.GetOrganizationId(), "setting default resource pool"); err != nil {
		return actions.FailedActionResult(err), nil
	}

	resp, err := a.comps.CoreSvc.Mgmt.ResourcePool.UpdateOrgDefaultResourcePool(ctx, req)
	if err != nil {
		return actions.FailedActionResult(err), nil
	}

	return actions.RunningActionResult(fmt.Sprintf("sent request to set default resource pool: %d", resp.GetDefaultResourcePoolId()), nil), nil
}

func (a *SetDefaultResourcePool) Result(ctx context.Context, instance *opent.Instance) (*actions.ActionResult, error) {
	return actions.SucceededActionResult(nil), nil
}

func (a *SetDefaultResourcePool) getParam(instance *opent.Instance) (*mgmtv1.UpdateOrgDefaultResourcePoolRequest, error) {
	paramMap := make(map[opent.ParamName]string)
	paramList := []opent.ParamName{
		opent.ParamProvider,
		opent.ParamRegionName,
	}
	uintParamMap := make(map[opent.ParamName]uint64)
	uintParamList := []opent.ParamName{
		opent.ParamTenantID,
		opent.ParamResourcePoolID,
	}

	for _, param := range paramList {
		paramMap[param], _ = instance.GetParam(param)
		if paramMap[param] == "" {
			return nil, fmt.Errorf("param %s is missing for setting default resource pool", param)
		}
	}
	for _, param := range uintParamList {
		val, err := instance.GetUintParam(param)
		if err != nil {
			return nil, fmt.Errorf("param %s is missing for setting default resource pool", param)
		}
		uintParamMap[param] = val
	}
	p := &mgmtv1.UpdateOrgDefaultResourcePoolRequest{
		ProviderId:            commonv1.CloudProvider_Name(commonv1.CloudProvider_Name_value[paramMap[opent.ParamProvider]]),
		RegionId:              toMgmtRegionID(paramMap[opent.ParamProvider], paramMap[opent.ParamRegionName]),
		OrganizationId:        uintParamMap[opent.ParamTenantID],
		DefaultResourcePoolId: uintParamMap[opent.ParamResourcePoolID],
	}
	return p, nil
}
