package backup

import (
	"context"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"
	"sigs.k8s.io/controller-runtime/pkg/log/zap"

	"github.com/tidbcloud/eks-provider/controllers/backup/task"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
)

func TestHandleClusterGone(t *testing.T) {
	scheme := runtime.NewScheme()
	require.NoError(t, cloudv1.AddToScheme(scheme))

	t.Run("deleting backup removes finalizer", func(t *testing.T) {
		now := metav1.NewTime(time.Now())
		backup := &cloudv1.Backup{
			ObjectMeta: metav1.ObjectMeta{
				Name:              "backup-1",
				Namespace:         "ns-1",
				DeletionTimestamp: &now,
				Finalizers:        []string{task.Finalizer},
			},
		}
		local := fake.NewClientBuilder().WithScheme(scheme).WithObjects(backup).Build()
		reconciler := &Reconciler{Client: local}

		_, err := reconciler.handleClusterGone(context.Background(), backup, zap.New())
		require.NoError(t, err)

		got := &cloudv1.Backup{}
		err = local.Get(context.Background(), client.ObjectKeyFromObject(backup), got)
		if !apierrors.IsNotFound(err) {
			require.NoError(t, err)
			assert.NotContains(t, got.Finalizers, task.Finalizer)
		}
	})

	t.Run("running backup is marked failed", func(t *testing.T) {
		backup := &cloudv1.Backup{
			ObjectMeta: metav1.ObjectMeta{Name: "backup-2", Namespace: "ns-1"},
			Status:     cloudv1.BackupStatus{Phase: cloudv1.BackupRunning},
		}
		local := fake.NewClientBuilder().
			WithScheme(scheme).
			WithObjects(backup).
			WithStatusSubresource(backup).
			Build()
		reconciler := &Reconciler{Client: local}

		_, err := reconciler.handleClusterGone(context.Background(), backup, zap.New())
		require.NoError(t, err)

		got := &cloudv1.Backup{}
		require.NoError(t, local.Get(context.Background(), client.ObjectKeyFromObject(backup), got))
		assert.Equal(t, cloudv1.BackupFailed, got.Status.Phase)
	})

	t.Run("complete backup is unchanged", func(t *testing.T) {
		backup := &cloudv1.Backup{
			ObjectMeta: metav1.ObjectMeta{Name: "backup-3", Namespace: "ns-1"},
			Status:     cloudv1.BackupStatus{Phase: cloudv1.BackupComplete},
		}
		local := fake.NewClientBuilder().
			WithScheme(scheme).
			WithObjects(backup).
			WithStatusSubresource(backup).
			Build()
		reconciler := &Reconciler{Client: local}

		_, err := reconciler.handleClusterGone(context.Background(), backup, zap.New())
		require.NoError(t, err)
		assert.Equal(t, cloudv1.BackupComplete, backup.Status.Phase)
	})
}
