package cluster

import (
	"fmt"

	"k8s.io/apimachinery/pkg/api/equality"

	"github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/shared-provider/pkg/utils"
)

type mutationFilter interface {
	Allow(*cloudv1.Cluster) bool
	Reason(*cloudv1.Cluster) string
}

type whenPhaseIn []cloudv1.ClusterPhase

func (f whenPhaseIn) Allow(c *cloudv1.Cluster) bool {
	for _, phase := range f {
		if c.Status.Phase == phase {
			return true
		}
	}

	return false
}

func (f whenPhaseIn) Reason(c *cloudv1.Cluster) string {
	return fmt.Sprintf("cluster phase %s should in %+v", c.Status.Phase, f)
}

// mutateTidbCluster mutate the tidbcluster resource is necessary and possible.
func (r *reconcileContext) mutateTidbCluster(
	mutateFn func(tc *v1alpha1.TidbCluster) error, filters ...mutationFilter) (mutated bool, err error) {
	beforeMutation := r.tc.DeepCopy()
	if err := mutateFn(r.tc); err != nil {
		return false, err
	}
	if equality.Semantic.DeepEqual(beforeMutation, r.tc) {
		// no changed, skip updating
		return false, nil
	}
	for _, filter := range filters {
		if !filter.Allow(r.cluster) {
			r.V(4).Info("skip updating tc", "reason", filter.Reason(r.cluster))
			return false, &utils.RequeueAfterError{RequeueAfter: defaultWaitInterval}
		}
	}
	if err := r.Client.Update(r.ctx, r.tc); err != nil {
		return false, err
	}

	return true, nil
}
