package common

import (
	"context"
	"errors"
	"fmt"
	"time"

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

	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	_ "github.com/tidbcloud/infra-provider/regional-server/pkg/common/constants"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/controllers/vpcpeering/task"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/deploy"
)

type Guardian struct {
	*task.BaseTask
}

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

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

// Create ensures the Finalizer is correctly set.
func (t *Guardian) Create(ctx context.Context) deploy.Result {
	// Add finalizer
	if !controllerutil.ContainsFinalizer(t.VPCPeering, v1alpha1.FinalizerVPCPeering) {
		controllerutil.AddFinalizer(t.VPCPeering, v1alpha1.FinalizerVPCPeering)
		// Require immediate requeue without running other tasks
		return deploy.Panic(nil)
	}

	// check vpc phase before doing vpcpeering, may not correct.
	switch phase := t.VPC.Status.Phase; phase {
	case v1alpha1.VPCPhaseActive:
		// do nothing
	case "", v1alpha1.VPCPhaseCreating, v1alpha1.VPCPhasePending, v1alpha1.VPCPhaseReadyForCreate, v1alpha1.VPCPhaseFailed:
		// can requeue
		return deploy.Error(fmt.Errorf("vpc is not active, current status is %s", phase)).WithRequeuAfter(time.Minute)
	case v1alpha1.VPCPhaseDeleted, v1alpha1.VPCPhaseDeleting, v1alpha1.VPCPhaseReadyForDelete:
		// abort without requeue
		return deploy.Panic(fmt.Errorf("cannot do peering when vpc phase is %s", phase))
	default:
		// abort without requeue
		return deploy.Panic(fmt.Errorf("unexpected vpc phase during peering: %s", phase))
	}
	// abort with requeue
	if t.VPC.Status.VPC.VPCID == "" {
		return deploy.Panic(errors.New("vpc.status.vpcId is empty"))
	}

	if t.Internet.Status.Phase != v1alpha1.InternetPhaseActive {
		return deploy.Panic(fmt.Errorf("internet %s is not active, current phase is %s", t.Internet.Name, t.Internet.Status.Phase))
	}

	return deploy.Done()
}
