package cluster

import (
	"context"
	"fmt"
	"testing"
	"time"

	. "github.com/onsi/gomega"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	reconcileerr "github.com/tidbcloud/infra-api/controllers/common/error"
)

func TestPendingDelete(t *testing.T) {
	g := NewGomegaWithT(t)
	scheme := runtime.NewScheme()
	g.Expect(cloudv1.AddToScheme(scheme)).To(Succeed())

	// running backup will removed when cluster deleted
	backup := cloudv1.Backup{
		ObjectMeta: v1.ObjectMeta{
			Name:      "backup",
			Namespace: "default",
		},
		Status: cloudv1.BackupStatus{
			Phase: cloudv1.BackupRunning,
		},
	}

	// all restore will deleted
	restore := cloudv1.Restore{
		ObjectMeta: v1.ObjectMeta{
			Name:      "restore",
			Namespace: "default",
		},
		Status: cloudv1.RestoreStatus{
			Phase: cloudv1.RestoreFailed,
		},
	}
	// all import will deleted
	ipt := cloudv1.Import{
		ObjectMeta: v1.ObjectMeta{
			Name:      "restore",
			Namespace: "default",
		},
		Status: cloudv1.ImportStatus{
			Phase: cloudv1.ImportPrepare,
		},
	}

	// deleted cluster
	cluster := &cloudv1.Cluster{
		ObjectMeta: v1.ObjectMeta{
			Name:      "cluster",
			Namespace: "default",
		},
		Status: cloudv1.ClusterStatus{
			Phase: cloudv1.ClusterPhasePendingDelete,
		},
	}

	client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&backup, &restore, &ipt, cluster).Build()
	r := reconcileContext{
		ClusterReconciler: &ClusterReconciler{
			Client: client,
		},
		ClusterContext: ClusterContext{
			Target: cluster,
		},
	}

	g.Eventually(func() error {
		ctx := context.Background()
		err := r.pendingDelete(ctx)
		e, ok := err.(*reconcileerr.RequeueAfterError)
		if ok && e.Caused == nil {
			err := client.Get(ctx, types.NamespacedName{
				Namespace: cluster.Namespace,
				Name:      cluster.Name,
			}, cluster)
			if err != nil {
				return err
			}
			if cluster.Status.Phase == cloudv1.ClusterPhaseDeleting {
				if names, err := r.getNotFinishedBackupNames(); err != nil || len(names) > 0 {
					return fmt.Errorf("not finished backup should be removed")
				}
				if names, err := r.getRestoreNames(); err != nil || len(names) > 0 {
					return fmt.Errorf("restores should be removed")
				}
				if names, err := r.getImportNames(); err != nil || len(names) > 0 {
					return fmt.Errorf("import shoud be removed")
				}
				return nil
			} else {
				return fmt.Errorf("Wait cluster status from pendingDelete to deleting")
			}

		}
		return err
	}, 10*time.Second, 1*time.Second).Should(Succeed(), "backup import restore will clean up")
}
