package mastermgr

import (
	"context"

	"go.uber.org/multierr"
	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

	eksv1alpha1 "github.com/tidbcloud/eks-provider/api/v1alpha1"
	"github.com/tidbcloud/infra-provider/pkg/deploy"
)

type MasterDispatcher struct {
	*BaseTask
}

func NewMasterDispatcher(ctx *Context) *MasterDispatcher {
	return &MasterDispatcher{BaseTask: &BaseTask{Context: ctx}}
}

func (t *MasterDispatcher) Name() string {
	return "MasterDispatcher"
}

func (t *MasterDispatcher) Create(ctx context.Context) deploy.Result {
	if !t.HasActiveExecutor() {
		return deploy.Done()
	}

	availableMaster := t.getAvailableMaster()
	if availableMaster == nil {
		return deploy.Done()
	}

	err := t.dispatcherMasterToExecutor(ctx, availableMaster)
	return deploy.ErrorOrDone(err)
}

func (t *MasterDispatcher) dispatcherMasterToExecutor(ctx context.Context, availableMaster *eksv1alpha1.TiflowClusterMaster) error {
	var errs error
	for _, executor := range t.TiflowClusterExecutorList {
		err := t.dispatcherMasterToOneExecutor(ctx, &executor, availableMaster)
		if err != nil {
			errs = multierr.Append(errs, err)
			continue
		}
	}
	return errs
}

func (t *MasterDispatcher) dispatcherMasterToOneExecutor(
	ctx context.Context, executor *eksv1alpha1.TiflowClusterExecutor, availableMaster *eksv1alpha1.TiflowClusterMaster) error {
	_, err := controllerutil.CreateOrUpdate(ctx, t.Local, executor, func() error {
		if executor.Spec.TiflowClusterMasterName == "" {
			executor.Spec.TiflowClusterMasterName = availableMaster.Name
		}
		return nil
	})
	return err
}

func (t *MasterDispatcher) getAvailableMaster() *eksv1alpha1.TiflowClusterMaster {
	for _, master := range t.ActiveTiflowClusterMasterList {
		if !master.DeletionTimestamp.IsZero() {
			continue
		}
		if master.Status.Phase != eksv1alpha1.TiflowClusterMasterPhaseRunning {
			continue
		}
		return &master
	}
	return nil
}
