package regionaction

import (
	"context"
	"fmt"

	opent "github.com/tidbcloud/devops/entity/operation"
	"github.com/tidbcloud/devops/pkg/service/operation/actions"
	"google.golang.org/protobuf/encoding/protojson"

	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"
)

var (
	ActionUpdateRegion opent.ActionMetadata = opent.ActionMetadata{
		Name: "UpdateRegion",
		Type: opent.ActionTypeAuto,
	}
)

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

func NewUpdateRegion(comps *actions.Components) actions.AutoAction {
	return &updateRegion{comps: comps}
}

func (a *updateRegion) Metadata() opent.ActionMetadata {
	return ActionUpdateRegion
}

func (a *updateRegion) PreCheck(ctx context.Context, instance *opent.Instance) error {
	_, err := a.getParam(instance)
	return err
}

func (a *updateRegion) Start(ctx context.Context, instance *opent.Instance) (*actions.ActionResult, error) {
	req, err := a.getParam(instance)
	if err != nil {
		return actions.FailedActionResult(err), nil
	}

	_, err = a.comps.CoreSvc.Mgmt.Region.UpdateRegion(ctx, req)
	if err != nil {
		return actions.FailedActionResult(fmt.Errorf("update region failed: %w", err)), nil
	}

	return actions.SucceededActionResult(nil), nil // return succeeded directly
}

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

func (a *updateRegion) getParam(instance *opent.Instance) (*mgmtv1.UpdateRegionRequest, error) {
	data := instance.Params[opent.ParamUpdateRegionRequest]
	if data == "" {
		return nil, fmt.Errorf("missing required param")
	}

	req := &mgmtv1.UpdateRegionRequest{}
	err := protojson.Unmarshal([]byte(data), req)
	if err != nil {
		return nil, fmt.Errorf("unmarshal param failed: %w", err)
	}
	region := req.GetRegion().GetRegion()
	if region.GetServicePlan() == commonv1.ServicePlan_BYOC {
		return nil, fmt.Errorf("byoc region can not be updated")
	}
	for _, item := range region.GetRegionWhiteLists() {
		if item.GetServicePlan() == commonv1.ServicePlan_BYOC {
			return nil, fmt.Errorf("byoc region can not be updated")
		}
	}

	return req, nil
}
