package server

import (
	"context"
	"testing"
	"time"

	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
	apiv1 "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	"github.com/tidbcloud/cluster-service-ng/domain/entity"
	"github.com/tidbcloud/cluster-service-ng/domain/workflow/dag"
	executor_mocks "github.com/tidbcloud/cluster-service-ng/pkg/runtime/executor/mocks"
	"github.com/tidbcloud/cluster-service-ng/pkg/runtime/executorext"
	executorext_mocks "github.com/tidbcloud/cluster-service-ng/pkg/runtime/executorext/mocks"
	"github.com/tidbcloud/cluster-service-ng/pkg/storage/mysql/schema"
	repomocks "github.com/tidbcloud/cluster-service-ng/pkg/storage/repo/mocks"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

func TestDeleteManualBackupAllowsDeletedSharedPool(t *testing.T) {
	ctx := context.Background()
	manualBackupRepo := repomocks.NewManualBackupRepo(t)
	sharedPoolRepo := repomocks.NewSharedPoolRepo(t)
	dagInstanceFinder := executorext_mocks.NewDagInstanceFinder(t)
	dagExecutor := executor_mocks.NewRemoteExecutor(t)

	backup := &entity.ManualBackup{ManualBackup: schema.ManualBackup{
		BackupID:     "backup-1",
		ClusterID:    "cluster-1",
		SharedPoolID: "pool-1",
		Status:       schema.ManualBackupStatusSucceeded,
	}}
	deletedAt := time.Now()
	deletedPool := &entity.SharedPool{
		SharedPool: apiv1.SharedPool{Id: "pool-1"},
		DeletedAt:  &deletedAt,
	}

	manualBackupRepo.EXPECT().Load(ctx, "cluster-1", "backup-1", true).Return(backup, nil)
	sharedPoolRepo.EXPECT().Load(ctx, "pool-1", true).Return(deletedPool, nil)
	dagInstanceFinder.EXPECT().GetRunningDagInstance(ctx, dag.PlanCreateManualBackup, mock.Anything).
		Return(nil, executorext.DagInsNotFoundErr)
	dagInstanceFinder.EXPECT().GetRunningDagInstance(ctx, dag.PlanDeleteManualBackup, mock.Anything).
		Return(nil, executorext.DagInsNotFoundErr)
	dagExecutor.EXPECT().Submit(ctx, dag.PlanDeleteManualBackup, mock.Anything, "mb-del-cluster-1-backup-1").
		Return(nil)

	server := &serverImpl{
		manualBackupRepo:  manualBackupRepo,
		sharedPoolRepo:    sharedPoolRepo,
		dagInstanceFinder: dagInstanceFinder,
		dagExecutor:       dagExecutor,
	}
	err := server.DeleteManualBackup(ctx, &DeleteManualBackupInput{
		DeleteManualBackupRequest: &apiv1.DeleteManualBackupRequest{
			ClusterId: "cluster-1",
			BackupId:  "backup-1",
		},
	})
	require.NoError(t, err)
}

func TestDeleteManualBackupRejectsPausedLivingSharedPool(t *testing.T) {
	ctx := context.Background()
	manualBackupRepo := repomocks.NewManualBackupRepo(t)
	sharedPoolRepo := repomocks.NewSharedPoolRepo(t)

	backup := &entity.ManualBackup{ManualBackup: schema.ManualBackup{
		BackupID:     "backup-1",
		ClusterID:    "cluster-1",
		SharedPoolID: "pool-1",
		Status:       schema.ManualBackupStatusSucceeded,
	}}
	pausedPool := &entity.SharedPool{
		SharedPool:            apiv1.SharedPool{Id: "pool-1"},
		PauseResumeState:      entity.PauseResumeStatePaused,
		SuspendComputeDesired: true,
	}

	manualBackupRepo.EXPECT().Load(ctx, "cluster-1", "backup-1", true).Return(backup, nil)
	sharedPoolRepo.EXPECT().Load(ctx, "pool-1", true).Return(pausedPool, nil)

	server := &serverImpl{
		manualBackupRepo: manualBackupRepo,
		sharedPoolRepo:   sharedPoolRepo,
	}
	err := server.DeleteManualBackup(ctx, &DeleteManualBackupInput{
		DeleteManualBackupRequest: &apiv1.DeleteManualBackupRequest{
			ClusterId: "cluster-1",
			BackupId:  "backup-1",
		},
	})
	require.Equal(t, codes.FailedPrecondition, status.Code(err))
}
