package executor

import (
	"context"
	"fmt"

	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

	eksv1alpha1 "github.com/tidbcloud/eks-provider/api/v1alpha1"
	"github.com/tidbcloud/eks-provider/controllers/tiflow/task"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-provider/pkg/deploy"
	"github.com/tidbcloud/infra-provider/pkg/util"
)

// Guardian adds and removes the finalizer of the Cluster.
type Guardian struct {
	*BaseTask
}

func NewGuardian(ctx *Context) *Guardian {
	return &Guardian{BaseTask: &BaseTask{Context: ctx}}
}

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

func (t *Guardian) Create(ctx context.Context) deploy.Result {
	// prevent reconciling objects from different regions
	if t.Network.Spec.Region != t.Config.Network.Region {
		return deploy.Panic(nil)
	}
	// ignore resource that doesn't belong to this region
	if !util.ContainsRegionLabel(t.TiflowClusterExecutor) {
		if ok, err := util.CheckNetworkRegion(t.Config.Network.Region, t.Network); err != nil {
			return deploy.Panic(err)
		} else if !ok {
			return deploy.Panic(nil)
		}
		// ensure the object contains the region label
		if !util.EnsureRegion(t.TiflowClusterExecutor, t.Network.Spec.Region) {
			return deploy.Panic(nil).WithRequeuAfter(0)
		}
	}
	if !controllerutil.ContainsFinalizer(t.TiflowClusterExecutor, task.Finalizer) {
		controllerutil.AddFinalizer(t.TiflowClusterExecutor, task.Finalizer)
		// Require immediate requeue without running other tasks
		return deploy.Panic(nil).WithRequeuAfter(0)
	}

	switch phase := t.TiflowClusterExecutor.Status.Phase; phase {
	case "", eksv1alpha1.TiflowClusterExecutorPhasePending:
		t.TiflowClusterExecutor.Status.Phase = eksv1alpha1.TiflowClusterExecutorPhasePending
		err := t.readyToCreate(ctx)
		if err != nil {
			return deploy.Panic(fmt.Errorf("tiflow executor executor is not ready to create: %v", err))
		}
		t.TiflowClusterExecutor.Status.Phase = eksv1alpha1.TiflowClusterExecutorPhaseCreating
	case eksv1alpha1.TiflowClusterExecutorPhaseCreating, eksv1alpha1.TiflowClusterExecutorPhaseRunning, eksv1alpha1.TiflowClusterExecutorPhaseScaling:
	default:
		return deploy.Panic(fmt.Errorf("unexpected tiflow cluster executor phase during creation: %s", phase))
	}
	return deploy.Done()
}

func (t *Guardian) readyToCreate(ctx context.Context) error {
	if phase := t.Network.Status.Phase; phase != cloudv1.NetworkPhaseNormal {
		return fmt.Errorf("network phase not ready: %s", phase)
	}
	return nil
}

func (t *Guardian) Delete(ctx context.Context) deploy.Result {
	switch phase := t.TiflowClusterExecutor.Status.Phase; phase {
	case eksv1alpha1.TiflowClusterExecutorPhasePending,
		eksv1alpha1.TiflowClusterExecutorPhaseCreating,
		eksv1alpha1.TiflowClusterExecutorPhasePendingDelete,
		eksv1alpha1.TiflowClusterExecutorPhaseRunning,
		eksv1alpha1.TiflowClusterExecutorPhaseScaling,
		"":
		t.TiflowClusterExecutor.Status.Phase = eksv1alpha1.TiflowClusterExecutorPhasePendingDelete
		// Require immediate requeue without running other tasks
		err := t.readyToDelete(ctx)
		if err != nil {
			return deploy.Panic(fmt.Errorf("tiflow cluster executor is not ready to delete: %v", err))
		}
		t.TiflowClusterExecutor.Status.Phase = eksv1alpha1.TiflowClusterExecutorPhaseDeleting
	case eksv1alpha1.TiflowClusterExecutorPhaseDeleting:
	default:
		return deploy.Panic(fmt.Errorf("unexpected cluster phase during deletion: %s", phase))
	}
	return deploy.Done()
}

func (t *Guardian) readyToDelete(ctx context.Context) error {
	return nil
}
