package dataplane

import (
	"context"
	"testing"

	"github.com/go-logr/logr/testr"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/config"
	"github.com/tidbcloud/infra-provider/regional-server/pkg/consts"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/client-go/tools/record"
	"k8s.io/client-go/util/retry"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"
	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

func TestCreateDataPlane(t *testing.T) {
	s := runtime.NewScheme()
	require.NoError(t, v1alpha1.AddToScheme(s))
	logger := testr.New(t)
	rootConfig := buildConfig()
	tmplConfig := config.TemplatesConfig{}
	kubeClient := fake.NewClientBuilder().WithScheme(s).
		WithStatusSubresource(&v1alpha1.DataPlane{}, &v1alpha1.VPC{}, &v1alpha1.Internet{}, &v1alpha1.APPBox{}).
		Build()
	dr := NewDataPlaneReconciler(
		kubeClient,
		logger,
		s,
		record.NewFakeRecorder(1024),
		rootConfig,
		tmplConfig)

	ctx := context.TODO()
	dataPlane := buildDataPlane()
	dataPlane.Annotations = map[string]string{v1alpha1.AnnotationKeyEnableCapacityPlanner: "true"}
	err := kubeClient.Create(ctx, dataPlane)
	require.NoError(t, err)

	req := reconcile.Request{
		NamespacedName: types.NamespacedName{
			Namespace: "dev-us-west-2",
			Name:      "dataplane-test",
		},
	}

	// add finalizer
	result, err := dr.Reconcile(ctx, req)
	assert.NoError(t, err)
	assert.True(t, result.Requeue)
	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(dataPlane), dataPlane)
	assert.NoError(t, err)
	assert.True(t, controllerutil.ContainsFinalizer(dataPlane, v1alpha1.Finalizer))

	// create vpc
	result, err = dr.Reconcile(ctx, req)
	assert.NoError(t, err)
	assert.True(t, result.Requeue)
	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(dataPlane), dataPlane)
	assert.NoError(t, err)
	assert.Equal(t, v1alpha1.DataPlanePhaseCreating, dataPlane.Status.Phase)
	assert.NotNil(t, dataPlane.Status.Vpc)
	assert.NotEmpty(t, dataPlane.Status.Vpc.Name)

	// check vpc created
	vpc := &v1alpha1.VPC{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: dataPlane.Status.Vpc.Namespace,
			Name:      dataPlane.Status.Vpc.Name,
		},
	}
	err = retry.OnError(retry.DefaultRetry, defaultRetriable, func() error {
		return kubeClient.Get(ctx, client.ObjectKeyFromObject(vpc), vpc)
	})
	assert.NoError(t, err)

	// vpc is active, create internet
	vpc.Status.Phase = v1alpha1.VPCPhaseActive
	err = retry.OnError(retry.DefaultRetry, defaultRetriable, func() error {
		return kubeClient.Status().Update(ctx, vpc)
	})
	assert.NoError(t, err)
	result, err = dr.Reconcile(ctx, req)
	assert.NoError(t, err)
	assert.True(t, result.Requeue)
	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(dataPlane), dataPlane)
	assert.NoError(t, err)
	assert.Equal(t, v1alpha1.DataPlanePhaseCreating, dataPlane.Status.Phase)
	assert.NotNil(t, dataPlane.Status.Internet)
	assert.NotEmpty(t, dataPlane.Status.Internet.Name)

	// check internet created
	internet := &v1alpha1.Internet{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: dataPlane.Status.Internet.Namespace,
			Name:      dataPlane.Status.Internet.Name,
		},
	}
	err = retry.OnError(retry.DefaultRetry, defaultRetriable, func() error {
		return kubeClient.Get(ctx, client.ObjectKeyFromObject(internet), internet)
	})
	assert.NoError(t, err)

	// internet is active, create appbox
	internet.Status.Phase = v1alpha1.InternetPhaseActive
	err = retry.OnError(retry.DefaultRetry, defaultRetriable, func() error {
		return kubeClient.Status().Update(ctx, internet)
	})
	assert.NoError(t, err)
	result, err = dr.Reconcile(ctx, req)
	assert.NoError(t, err)
	assert.True(t, result.Requeue)
	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(dataPlane), dataPlane)
	assert.NoError(t, err)
	assert.Equal(t, v1alpha1.DataPlanePhaseCreating, dataPlane.Status.Phase)
	assert.NotNil(t, dataPlane.Status.AppBox)
	assert.NotEmpty(t, dataPlane.Status.AppBox.Name)

	// check appbox created
	appBox := &v1alpha1.APPBox{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: dataPlane.Status.AppBox.Namespace,
			Name:      dataPlane.Status.AppBox.Name,
		},
	}
	err = retry.OnError(retry.DefaultRetry, defaultRetriable, func() error {
		return kubeClient.Get(ctx, client.ObjectKeyFromObject(appBox), appBox)
	})
	assert.NoError(t, err)
	require.NotNil(t, appBox.Spec.PCA)
	assert.Equal(t, dataPlane.Spec.PCA, appBox.Spec.PCA)
	assert.Equal(t, "true", appBox.Annotations[v1alpha1.AnnotationKeyEnableCapacityPlanner])

	// appbox is active, dataplane become active
	appBox.Status.Phase = v1alpha1.APPBoxPhaseActive
	err = retry.OnError(retry.DefaultRetry, defaultRetriable, func() error {
		return kubeClient.Status().Update(ctx, appBox)
	})
	assert.NoError(t, err)
	result, err = dr.Reconcile(ctx, req)
	assert.NoError(t, err)
	assert.True(t, result.IsZero())
	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(dataPlane), dataPlane)
	assert.NoError(t, err)
	assert.Equal(t, v1alpha1.DataPlanePhaseActive, dataPlane.Status.Phase)
}

func TestDataPlaneReconcilerFailsClosedOnUnknownOwnershipMode(t *testing.T) {
	t.Parallel()

	s := runtime.NewScheme()
	require.NoError(t, v1alpha1.AddToScheme(s))
	kubeClient := fake.NewClientBuilder().WithScheme(s).Build()
	dataPlane := buildDataPlane()
	dataPlane.Spec.OwnershipMode = "FutureOwnership"
	require.NoError(t, kubeClient.Create(context.Background(), dataPlane))
	reconciler := NewDataPlaneReconciler(
		kubeClient,
		testr.New(t),
		s,
		record.NewFakeRecorder(16),
		buildConfig(),
		config.TemplatesConfig{},
	)

	_, err := reconciler.Reconcile(context.Background(), reconcile.Request{NamespacedName: client.ObjectKeyFromObject(dataPlane)})
	require.ErrorContains(t, err, "unknown stored dataplane ownership mode")

	var vpcs v1alpha1.VPCList
	require.NoError(t, kubeClient.List(context.Background(), &vpcs))
	assert.Empty(t, vpcs.Items, "unknown ownership mode must stop before child reconciliation")
}

func TestDataPlaneReconcilerRejectsOwnershipModeMutation(t *testing.T) {
	t.Parallel()

	s := runtime.NewScheme()
	require.NoError(t, v1alpha1.AddToScheme(s))
	dataPlane := buildDataPlane()
	dataPlane.Spec.OwnershipMode = v1alpha1.DataPlaneOwnershipModeSinglePool
	kubeClient := fake.NewClientBuilder().WithScheme(s).WithObjects(dataPlane).Build()
	reconciler := NewDataPlaneReconciler(
		kubeClient,
		testr.New(t),
		s,
		record.NewFakeRecorder(16),
		buildConfig(),
		config.TemplatesConfig{},
	)

	mutated := dataPlane.DeepCopy()
	mutated.Spec.OwnershipMode = v1alpha1.DataPlaneOwnershipModeMultiPool
	err := reconciler.updateDataPlane(
		context.Background(),
		testr.New(t),
		mutated,
		v1alpha1.DataPlaneOwnershipModeSinglePool,
	)
	require.ErrorContains(t, err, "immutable")

	stored := new(v1alpha1.DataPlane)
	require.NoError(t, kubeClient.Get(context.Background(), client.ObjectKeyFromObject(dataPlane), stored))
	assert.Equal(t, v1alpha1.DataPlaneOwnershipModeSinglePool, stored.Spec.OwnershipMode)
}

func TestDataPlaneReconcilerPropagatesCloudTagTriggersWithoutMutatingChildSpecTags(t *testing.T) {
	s := runtime.NewScheme()
	require.NoError(t, v1alpha1.AddToScheme(s))
	logger := testr.New(t)
	rootConfig := buildConfig()
	tmplConfig := config.TemplatesConfig{}

	dataPlane := buildDataPlane()
	controllerutil.AddFinalizer(dataPlane, v1alpha1.Finalizer)
	dataPlane.Status.Phase = v1alpha1.DataPlanePhaseActive
	dataPlane.Spec.CloudTags = map[string]string{
		"tags.tidbcloud.com/owner":       "platform",
		"tags.tidbcloud.com/cost-center": "cc-1",
	}
	dataPlane.Status.Vpc = &v1alpha1.Reference{Name: "vpc-1", Namespace: dataPlane.Namespace}
	dataPlane.Status.Internet = &v1alpha1.Reference{Name: "internet-1", Namespace: dataPlane.Namespace}
	dataPlane.Status.AppBox = &v1alpha1.Reference{Name: "appbox-1", Namespace: dataPlane.Namespace}

	vpc := &v1alpha1.VPC{ObjectMeta: metav1.ObjectMeta{Name: "vpc-1", Namespace: dataPlane.Namespace}}
	vpc.Status.Phase = v1alpha1.VPCPhaseActive
	internet := &v1alpha1.Internet{ObjectMeta: metav1.ObjectMeta{Name: "internet-1", Namespace: dataPlane.Namespace}}
	internet.Status.Phase = v1alpha1.InternetPhaseActive
	appBox := &v1alpha1.APPBox{ObjectMeta: metav1.ObjectMeta{Name: "appbox-1", Namespace: dataPlane.Namespace}}
	appBox.Status.Phase = v1alpha1.APPBoxPhaseActive
	bucket := &v1alpha1.Bucket{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "bucket-1",
			Namespace: dataPlane.Namespace,
			Labels: map[string]string{
				v1alpha1.DataPlaneIDKey: dataPlane.Name,
			},
		},
		Spec: v1alpha1.BucketSpec{
			DataplaneId: dataPlane.Name,
			Tags: map[string]string{
				"tags.tidbcloud.com/owner": "bucket-owner",
			},
		},
	}
	loadBalancer := &v1alpha1.LoadBalancer{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "lb-1",
			Namespace: dataPlane.Namespace,
			Labels: map[string]string{
				v1alpha1.DataPlaneIDKey: dataPlane.Name,
			},
		},
		Spec: v1alpha1.LoadBalancerSpec{
			DataPlane: v1alpha1.Reference{Name: dataPlane.Name, Namespace: dataPlane.Namespace},
			Tags: map[string]string{
				"tags.tidbcloud.com/owner": "lb-owner",
			},
		},
	}
	privateLinkService := &v1alpha1.PrivateLinkService{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "pls-1",
			Namespace: dataPlane.Namespace,
			Labels: map[string]string{
				v1alpha1.DataPlaneIDKey: dataPlane.Name,
			},
		},
		Spec: v1alpha1.PrivateLinkServiceSpec{
			VPCRef: v1alpha1.Reference{Name: vpc.Name, Namespace: vpc.Namespace},
			Tags: map[string]string{
				"tags.tidbcloud.com/owner": "pls-owner",
			},
		},
	}
	privateLinkEndpoint := &v1alpha1.PrivateLinkEndpoint{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "ple-1",
			Namespace: dataPlane.Namespace,
			Labels: map[string]string{
				v1alpha1.DataPlaneIDKey: dataPlane.Name,
			},
		},
		Spec: v1alpha1.PrivateLinkEndpointSpec{
			VPCRef: v1alpha1.Reference{Name: vpc.Name, Namespace: vpc.Namespace},
			Tags: map[string]string{
				"tags.tidbcloud.com/owner": "ple-owner",
			},
		},
	}
	vpcPeering := &v1alpha1.VPCPeering{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "vpcpeering-1",
			Namespace: dataPlane.Namespace,
			Labels: map[string]string{
				v1alpha1.DataPlaneIDKey: dataPlane.Name,
			},
		},
		Spec: v1alpha1.VPCPeeringSpec{
			DataPlane: v1alpha1.Reference{Name: dataPlane.Name, Namespace: dataPlane.Namespace},
		},
	}
	kubeClient := fake.NewClientBuilder().WithScheme(s).
		WithStatusSubresource(&v1alpha1.DataPlane{}, &v1alpha1.VPC{}, &v1alpha1.Internet{}, &v1alpha1.APPBox{}).
		WithObjects(dataPlane, vpc, internet, appBox, bucket, loadBalancer, privateLinkService, privateLinkEndpoint, vpcPeering).
		Build()
	dr := NewDataPlaneReconciler(
		kubeClient,
		logger,
		s,
		record.NewFakeRecorder(1024),
		rootConfig,
		tmplConfig,
	)

	_, err := dr.Reconcile(context.Background(), reconcile.Request{NamespacedName: client.ObjectKeyFromObject(dataPlane)})
	require.NoError(t, err)

	assertLabelsUpdated := func(obj client.Object) {
		t.Helper()
		require.NoError(t, kubeClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj))
		assert.Equal(t, "platform", obj.GetLabels()["tags.tidbcloud.com/owner"])
		assert.Equal(t, "cc-1", obj.GetLabels()["tags.tidbcloud.com/cost-center"])
		assert.Empty(t, obj.GetAnnotations()[consts.AnnotationKeyCloudTagsReconcileTrigger])
	}
	assertLabelsUpdated(vpc)
	assertLabelsUpdated(internet)
	assertLabelsUpdated(appBox)

	assertTriggered := func(obj client.Object) {
		t.Helper()
		require.NoError(t, kubeClient.Get(context.Background(), client.ObjectKeyFromObject(obj), obj))
		assert.Empty(t, obj.GetLabels()["tags.tidbcloud.com/owner"])
		assert.Empty(t, obj.GetLabels()["tags.tidbcloud.com/cost-center"])
		assert.NotEmpty(t, obj.GetAnnotations()[consts.AnnotationKeyCloudTagsReconcileTrigger])
	}
	assertTriggered(bucket)
	assertTriggered(loadBalancer)
	assertTriggered(privateLinkService)
	assertTriggered(privateLinkEndpoint)
	assertTriggered(vpcPeering)

	assert.Equal(t, "bucket-owner", bucket.Spec.Tags["tags.tidbcloud.com/owner"])
	assert.Equal(t, "lb-owner", loadBalancer.Spec.Tags["tags.tidbcloud.com/owner"])
	assert.Equal(t, "pls-owner", privateLinkService.Spec.Tags["tags.tidbcloud.com/owner"])
	assert.Equal(t, "ple-owner", privateLinkEndpoint.Spec.Tags["tags.tidbcloud.com/owner"])
}

func buildConfig() config.RootConfig {
	return config.RootConfig{
		ControllerConfig: config.ControllerConfig{
			Provider: consts.ProviderTypeEKS,
			Env:      "dev",
			RegionConfig: config.RegionConfig{
				LogicalRegionName: "us-west-2-wl",
				Name:              "us-west-2",
				Zones:             []string{"us-west-2a", "us-west-2b", "us-west-2c"},
			},
			APPBoxConfig: config.APPBoxConfig{
				K8sVersion: "v1.30.0",
			},
			DataPlaneRoleName:      "dataplane-manager",
			AWSDataPlaneExternalID: "123",
		},
	}
}

func TestDeleteDataPlane(t *testing.T) {
	s := runtime.NewScheme()
	require.NoError(t, v1alpha1.AddToScheme(s))
	logger := testr.New(t)
	rootConfig := buildConfig()
	tmplConfig := config.TemplatesConfig{}
	kubeClient := fake.NewClientBuilder().WithScheme(s).
		WithStatusSubresource(&v1alpha1.DataPlane{}, &v1alpha1.VPC{}, &v1alpha1.Internet{}, &v1alpha1.APPBox{}).
		Build()
	dr := NewDataPlaneReconciler(
		kubeClient,
		logger,
		s,
		record.NewFakeRecorder(1024),
		rootConfig,
		tmplConfig)

	ctx := context.TODO()
	dataPlane := buildDataPlane()
	err := kubeClient.Create(ctx, dataPlane)
	require.NoError(t, err)

	req := reconcile.Request{
		NamespacedName: types.NamespacedName{
			Namespace: "dev-us-west-2",
			Name:      "dataplane-test",
		},
	}

	// add finalizer
	_, err = dr.Reconcile(ctx, req)
	assert.NoError(t, err)
	// create vpc, internet, appbox
	_, err = dr.Reconcile(ctx, req)
	assert.NoError(t, err)

	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(dataPlane), dataPlane)
	assert.NoError(t, err)
	assert.True(t, controllerutil.ContainsFinalizer(dataPlane, v1alpha1.Finalizer))
	assert.NotNil(t, dataPlane.Status.Vpc)

	// set vpc active
	vpc := &v1alpha1.VPC{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: dataPlane.Status.Vpc.Namespace,
			Name:      dataPlane.Status.Vpc.Name,
		},
	}
	err = retry.OnError(retry.DefaultRetry, defaultRetriable, func() error {
		if err := kubeClient.Get(ctx, client.ObjectKeyFromObject(vpc), vpc); err != nil {
			return err
		}
		vpc.Status.Phase = v1alpha1.VPCPhaseActive
		return kubeClient.Status().Update(ctx, vpc)
	})
	assert.NoError(t, err)
	// vpc active, reconcile to create internet
	_, err = dr.Reconcile(ctx, req)
	assert.NoError(t, err)
	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(dataPlane), dataPlane)
	assert.NoError(t, err)
	assert.NotNil(t, dataPlane.Status.Internet)

	// set internet active
	assert.NotNil(t, dataPlane.Status.Internet)
	internet := &v1alpha1.Internet{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: dataPlane.Status.Internet.Namespace,
			Name:      dataPlane.Status.Internet.Name,
		},
	}
	err = retry.OnError(retry.DefaultRetry, defaultRetriable, func() error {
		if err := kubeClient.Get(ctx, client.ObjectKeyFromObject(internet), internet); err != nil {
			return err
		}
		internet.Status.Phase = v1alpha1.InternetPhaseActive
		return kubeClient.Status().Update(ctx, internet)
	})
	assert.NoError(t, err)
	// internet active, reconcile to create appbox
	_, err = dr.Reconcile(ctx, req)
	assert.NoError(t, err)
	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(dataPlane), dataPlane)
	assert.NoError(t, err)
	assert.NotNil(t, dataPlane.Status.AppBox)
	appBox := &v1alpha1.APPBox{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: dataPlane.Status.AppBox.Namespace,
			Name:      dataPlane.Status.AppBox.Name,
		},
	}
	err = retry.OnError(retry.DefaultRetry, defaultRetriable, func() error {
		if err := kubeClient.Get(ctx, client.ObjectKeyFromObject(vpc), vpc); err != nil {
			return err
		}
		if err := kubeClient.Get(ctx, client.ObjectKeyFromObject(internet), internet); err != nil {
			return err
		}
		if err := kubeClient.Get(ctx, client.ObjectKeyFromObject(appBox), appBox); err != nil {
			return err
		}
		return nil
	})
	assert.NoError(t, err)

	vpcPeering := &v1alpha1.VPCPeering{
		ObjectMeta: metav1.ObjectMeta{
			Name:       "vpcpeering-test",
			Namespace:  dataPlane.Namespace,
			Finalizers: []string{v1alpha1.FinalizerVPCPeering},
			Labels: map[string]string{
				v1alpha1.DataPlaneIDKey: dataPlane.Name,
				v1alpha1.VPCNameKey:     vpc.Name,
			},
		},
		Spec: v1alpha1.VPCPeeringSpec{
			DataPlane: v1alpha1.Reference{
				Namespace: dataPlane.Namespace,
				Name:      dataPlane.Name,
			},
			Provider: consts.ProviderTypeEKS,
			Region:   rootConfig.RegionConfig.Name,
			Target: v1alpha1.Target{AWS: &v1alpha1.AWS{
				AccountID: "5678",
				VpcID:     "vpc-peer",
				PeerCIDR:  "10.0.0.0/16",
				Region:    "us-west-2",
			}},
		},
	}
	err = kubeClient.Create(ctx, vpcPeering)
	assert.NoError(t, err)

	controllerutil.AddFinalizer(vpc, v1alpha1.Finalizer)
	controllerutil.AddFinalizer(internet, v1alpha1.Finalizer)
	controllerutil.AddFinalizer(appBox, v1alpha1.Finalizer)
	err = retry.OnError(retry.DefaultRetry, defaultRetriable, func() error {
		if err := kubeClient.Update(ctx, vpc); err != nil {
			return err
		}
		if err := kubeClient.Update(ctx, internet); err != nil {
			return err
		}
		if err := kubeClient.Update(ctx, appBox); err != nil {
			return err
		}
		return nil
	})
	assert.NoError(t, err)

	// Add deletion confirmation annotation before deleting
	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(dataPlane), dataPlane)
	assert.NoError(t, err)
	if dataPlane.Annotations == nil {
		dataPlane.Annotations = make(map[string]string)
	}
	dataPlane.Annotations[consts.AnnotationKeyConfirmDeletion] = "true"
	err = kubeClient.Update(ctx, dataPlane)
	assert.NoError(t, err)

	// Re-fetch to get updated resource version
	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(dataPlane), dataPlane)
	assert.NoError(t, err)
	// Verify finalizer is still present before deletion
	assert.True(t, controllerutil.ContainsFinalizer(dataPlane, v1alpha1.Finalizer), "finalizer should exist before delete")

	// delete dataplane - fake client will set DeletionTimestamp automatically
	err = kubeClient.Delete(ctx, dataPlane)
	assert.NoError(t, err)
	result, err := dr.Reconcile(ctx, req)
	assert.NoError(t, err)
	assert.True(t, result.Requeue)
	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(dataPlane), dataPlane)
	assert.NoError(t, err)
	assert.Equal(t, v1alpha1.DataPlanePhaseDeleting, dataPlane.Status.Phase)
	assert.True(t, controllerutil.ContainsFinalizer(dataPlane, v1alpha1.Finalizer))

	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(vpc), vpc)
	assert.NoError(t, err)
	assert.NotNil(t, vpc.DeletionTimestamp)
	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(internet), internet)
	assert.NoError(t, err)
	assert.NotNil(t, internet.DeletionTimestamp)
	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(appBox), appBox)
	assert.NoError(t, err)
	assert.NotNil(t, appBox.DeletionTimestamp)
	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(vpcPeering), vpcPeering)
	assert.NoError(t, err)
	assert.Equal(t, consts.AnnoValTrue, vpcPeering.Annotations[consts.AnnotationKeyConfirmDeletion])
	assert.NotNil(t, vpcPeering.DeletionTimestamp)

	controllerutil.RemoveFinalizer(vpcPeering, v1alpha1.FinalizerVPCPeering)
	controllerutil.RemoveFinalizer(vpc, v1alpha1.Finalizer)
	controllerutil.RemoveFinalizer(internet, v1alpha1.Finalizer)
	controllerutil.RemoveFinalizer(appBox, v1alpha1.Finalizer)
	err = retry.OnError(retry.DefaultRetry, defaultRetriable, func() error {
		if err := kubeClient.Update(ctx, vpcPeering); err != nil {
			return err
		}
		if err := kubeClient.Update(ctx, vpc); err != nil {
			return err
		}
		if err := kubeClient.Update(ctx, internet); err != nil {
			return err
		}
		if err := kubeClient.Update(ctx, appBox); err != nil {
			return err
		}
		return nil
	})
	assert.NoError(t, err)
	result, err = dr.Reconcile(ctx, req)
	assert.NoError(t, err)
	assert.True(t, result.IsZero())
	err = kubeClient.Get(ctx, client.ObjectKeyFromObject(dataPlane), dataPlane)
	assert.True(t, apierrors.IsNotFound(err))
}

func buildDataPlane() *v1alpha1.DataPlane {
	return &v1alpha1.DataPlane{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: "dev-us-west-2",
			Name:      "dataplane-test",
		},
		Spec: v1alpha1.DataPlaneSpec{
			CloudTags: map[string]string{
				"region": "us-west-2",
			},
			PCA: &v1alpha1.PCAConfig{
				CAIdentifier: "arn:aws:acm-pca:us-west-2:123456789012:certificate-authority/pca-1",
			},
			VpcCidr:           "192.168.0.0/24",
			AvailabilityZones: []string{"us-west-2a", "us-west-2b", "us-west-2c"},
			AccountRef: v1alpha1.AccountReference{
				ProviderConfigName: "1234",
				AccountID:          "1234",
				Role:               "dataplane-manager",
			},
		},
	}
}

func defaultRetriable(err error) bool {
	return true
}
