package service

import (
	"context"
	"testing"

	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/pkgv2/bizerr"
	"github.com/tidbcloud/serverless-service/internal/domain/constant"
	"github.com/tidbcloud/serverless-service/internal/domain/entity"
	"github.com/tidbcloud/serverless-service/internal/domain/facade/mock_facade"
	"github.com/tidbcloud/serverless-service/internal/domain/repo/mock_repo"
	"go.uber.org/mock/gomock"
)

func TestRepairBackupScheduleSnapshotFields(t *testing.T) {
	ctrl := gomock.NewController(t)
	scheduleRepo := mock_repo.NewMockBackupScheduleRepo(ctrl)
	mgmtSvc := mock_facade.NewMockMgmtSvcFacade(ctrl)
	billingFacade := mock_facade.NewMockBillingFacade(ctrl)
	worker := &backupWorker{
		backupSchedule: scheduleRepo,
		mgmtSvc:        mgmtSvc,
		billingFacade:  billingFacade,
	}
	schedule := &entity.BackupSchedule{
		ID:        10,
		ClusterID: "2002",
	}

	scheduleRepo.EXPECT().List(gomock.Any(), entity.ListBackupScheduleOptions{
		IncludeDeleted:              true,
		IncompleteSnapshot:          true,
		IncompleteSnapshotBatchSize: backupScheduleSnapshotRepairBatchSize,
	}).Return([]*entity.BackupSchedule{schedule}, nil)
	mgmtSvc.EXPECT().GetClusterIncludeDeleted(gomock.Any(), uint64(2002)).Return(deletedCluster(), nil)
	billingFacade.EXPECT().GetInvoiceLimit(gomock.Any(), uint64(1001), uint64(2002)).Return(uint32(0), nil)
	scheduleRepo.EXPECT().Save(gomock.Any(), schedule).DoAndReturn(
		func(_ context.Context, saved *entity.BackupSchedule) (*entity.BackupSchedule, error) {
			require.Equal(t, testSourceToken, saved.SourceToken)
			require.Equal(t, constant.SERVERLESS_PLAN_STARTER_FREE, saved.ServicePlan)
			require.NotNil(t, saved.EnhancedEncryptionEnabled)
			require.NotNil(t, saved.ZoneRedundantEnabled)
			return saved, nil
		},
	)

	err := worker.repairBackupScheduleSnapshotFields(context.Background())

	require.NoError(t, err)
}

func TestRepairBackupScheduleSnapshotSkipsMissingCluster(t *testing.T) {
	ctrl := gomock.NewController(t)
	scheduleRepo := mock_repo.NewMockBackupScheduleRepo(ctrl)
	mgmtSvc := mock_facade.NewMockMgmtSvcFacade(ctrl)
	worker := &backupWorker{
		backupSchedule: scheduleRepo,
		mgmtSvc:        mgmtSvc,
	}
	schedule := &entity.BackupSchedule{ID: 10, ClusterID: "2002"}

	mgmtSvc.EXPECT().GetClusterIncludeDeleted(gomock.Any(), uint64(2002)).Return(
		nil,
		bizerr.New(bizerr.ErrCodeRecordNotFound, "cluster not found"),
	)

	err := worker.repairBackupScheduleSnapshot(context.Background(), schedule)

	require.NoError(t, err)
}

func TestRepairBackupScheduleSnapshotSkipsEmptySourceToken(t *testing.T) {
	ctrl := gomock.NewController(t)
	scheduleRepo := mock_repo.NewMockBackupScheduleRepo(ctrl)
	mgmtSvc := mock_facade.NewMockMgmtSvcFacade(ctrl)
	worker := &backupWorker{
		backupSchedule: scheduleRepo,
		mgmtSvc:        mgmtSvc,
	}
	schedule := &entity.BackupSchedule{ID: 10, ClusterID: "2002"}
	cluster := deletedCluster()
	cluster.GetServerlessCluster().GetCluster().UserPrefix = ""
	mgmtSvc.EXPECT().GetClusterIncludeDeleted(gomock.Any(), uint64(2002)).Return(cluster, nil)

	err := worker.repairBackupScheduleSnapshot(context.Background(), schedule)

	require.NoError(t, err)
}
