package br

import (
	"context"
	"testing"
	"time"

	"github.com/aws/smithy-go/ptr"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	clusterngv1beta "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	"go.uber.org/mock/gomock"
	"google.golang.org/protobuf/types/known/timestamppb"

	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	mockregionalserver "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/regionalserver/mock_regionalserver"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/entity"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/br"
	mockbrrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/br/mock_br"
	mockclusterrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/cluster/mock_cluster"
	mockregionrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/region/mock_region"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/workflow/common"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/infra/repoimpl/schema"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/pagination"
	mockworkflow "github.com/tidbcloud/tidb-management-service/utilities/workflow/mock_workflow"
)

func TestGetRestoreContextInfo(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	ctx := t.Context()

	tests := []struct {
		name           string
		req            *globalngv1.RestoreClusterRequest
		setupMocks     func(*mockclusterrepo.MockRepo, *mockbrrepo.MockBackupRepo)
		expectError    bool
		errorMsg       string
		validateResult func(*entity.Cluster, *entity.Cluster, *entity.Backup, *time.Time)
	}{
		{
			name: "successful snapshot restore - all valid",
			req: &globalngv1.RestoreClusterRequest{
				SourceClusterId: "123",
				TargetClusterId: "456",
				RestoreMode:     globalngv1.RestoreMode_RESTORE_MODE_SNAPSHOT,
				BackupId:        "789",
			},
			setupMocks: func(mockClusterRepo *mockclusterrepo.MockRepo, mockBackupRepo *mockbrrepo.MockBackupRepo) {
				sourceCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      123,
						OrganizationId: 100,
					},
				}
				targetCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      456,
						OrganizationId: 200,
					},
				}
				backup := &entity.Backup{
					Backup: &schema.Backup{
						ID:              789,
						ClusterId:       123,
						BackupSizeBytes: 1024 * 1024,
						State:           schema.BackupStateSuccess,
					},
				}

				// Mock source cluster get
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(123), true).
					Return(sourceCluster, nil)

				// Mock target cluster get
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(456), true).
					Return(targetCluster, nil)

				// Mock backup query
				mockBackupRepo.EXPECT().
					UnscopedQuery(gomock.Any(), gomock.Any(), gomock.Eq((*pagination.Page)(nil))).
					DoAndReturn(func(ctx context.Context, filter *br.QueryBackupsFilter, page *pagination.Page) ([]*entity.Backup, bizerr.BizError) {
						assert.Equal(t, []uint64{789}, filter.Ids)
						assert.Equal(t, ptr.Bool(false), filter.Deleted)
						return []*entity.Backup{backup}, nil
					})
			},
			expectError: false,
			validateResult: func(sourceCluster, targetCluster *entity.Cluster, backup *entity.Backup, pointInTime *time.Time) {
				assert.NotNil(t, sourceCluster)
				assert.NotNil(t, targetCluster)
				assert.NotNil(t, backup)
				assert.Nil(t, pointInTime)
				assert.Equal(t, uint64(123), sourceCluster.GetClusterId())
				assert.Equal(t, uint64(456), targetCluster.GetClusterId())
				assert.Equal(t, uint64(789), backup.ID)
			},
		},
		{
			name: "successful PITR restore - all valid",
			req: &globalngv1.RestoreClusterRequest{
				SourceClusterId: "123",
				TargetClusterId: "456",
				RestoreMode:     globalngv1.RestoreMode_RESTORE_MODE_PITR,
				PointInTime:     timestamppb.New(time.Date(2024, 1, 15, 12, 0, 0, 0, time.UTC)),
			},
			setupMocks: func(mockClusterRepo *mockclusterrepo.MockRepo, mockBackupRepo *mockbrrepo.MockBackupRepo) {
				sourceCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      123,
						OrganizationId: 100,
					},
				}
				targetCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      456,
						OrganizationId: 200,
					},
				}

				// Mock source cluster get
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(123), true).
					Return(sourceCluster, nil)

				// Mock target cluster get
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(456), true).
					Return(targetCluster, nil)
			},
			expectError: false,
			validateResult: func(sourceCluster, targetCluster *entity.Cluster, backup *entity.Backup, pointInTime *time.Time) {
				assert.NotNil(t, sourceCluster)
				assert.NotNil(t, targetCluster)
				assert.Nil(t, backup)
				assert.NotNil(t, pointInTime)
				assert.Equal(t, uint64(123), sourceCluster.GetClusterId())
				assert.Equal(t, uint64(456), targetCluster.GetClusterId())
				assert.Equal(t, time.Date(2024, 1, 15, 12, 0, 0, 0, time.UTC), *pointInTime)
			},
		},
		{
			name: "error - invalid source cluster id",
			req: &globalngv1.RestoreClusterRequest{
				SourceClusterId: "invalid",
				TargetClusterId: "456",
				RestoreMode:     globalngv1.RestoreMode_RESTORE_MODE_SNAPSHOT,
				BackupId:        "789",
			},
			setupMocks: func(mockClusterRepo *mockclusterrepo.MockRepo, mockBackupRepo *mockbrrepo.MockBackupRepo) {
				// No mocks needed since parsing fails first
			},
			expectError: true,
			errorMsg:    "failed to parse source cluster id",
		},
		{
			name: "error - invalid target cluster id",
			req: &globalngv1.RestoreClusterRequest{
				SourceClusterId: "123",
				TargetClusterId: "invalid",
				RestoreMode:     globalngv1.RestoreMode_RESTORE_MODE_SNAPSHOT,
				BackupId:        "789",
			},
			setupMocks: func(mockClusterRepo *mockclusterrepo.MockRepo, mockBackupRepo *mockbrrepo.MockBackupRepo) {
				sourceCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      123,
						OrganizationId: 100,
					},
				}

				// Mock source cluster get
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(123), true).
					Return(sourceCluster, nil)
			},
			expectError: true,
			errorMsg:    "failed to parse target cluster id",
		},
		{
			name: "error - source cluster not found",
			req: &globalngv1.RestoreClusterRequest{
				SourceClusterId: "123",
				TargetClusterId: "456",
				RestoreMode:     globalngv1.RestoreMode_RESTORE_MODE_SNAPSHOT,
				BackupId:        "789",
			},
			setupMocks: func(mockClusterRepo *mockclusterrepo.MockRepo, mockBackupRepo *mockbrrepo.MockBackupRepo) {
				// Mock source cluster get - returns error
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(123), true).
					Return(nil, bizerr.New(bizerr.ErrCodeRecordNotFound, "cluster not found"))
			},
			expectError: true,
			errorMsg:    "failed to get source cluster",
		},
		{
			name: "error - target cluster not found",
			req: &globalngv1.RestoreClusterRequest{
				SourceClusterId: "123",
				TargetClusterId: "456",
				RestoreMode:     globalngv1.RestoreMode_RESTORE_MODE_SNAPSHOT,
				BackupId:        "789",
			},
			setupMocks: func(mockClusterRepo *mockclusterrepo.MockRepo, mockBackupRepo *mockbrrepo.MockBackupRepo) {
				sourceCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      123,
						OrganizationId: 100,
					},
				}

				// Mock source cluster get
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(123), true).
					Return(sourceCluster, nil)

				// Mock target cluster get - returns error
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(456), true).
					Return(nil, bizerr.New(bizerr.ErrCodeRecordNotFound, "cluster not found"))
			},
			expectError: true,
			errorMsg:    "failed to get target cluster",
		},
		{
			name: "error - snapshot mode invalid backup id",
			req: &globalngv1.RestoreClusterRequest{
				SourceClusterId: "123",
				TargetClusterId: "456",
				RestoreMode:     globalngv1.RestoreMode_RESTORE_MODE_SNAPSHOT,
				BackupId:        "invalid",
			},
			setupMocks: func(mockClusterRepo *mockclusterrepo.MockRepo, mockBackupRepo *mockbrrepo.MockBackupRepo) {
				sourceCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      123,
						OrganizationId: 100,
					},
				}
				targetCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      456,
						OrganizationId: 200,
					},
				}

				// Mock source cluster get
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(123), true).
					Return(sourceCluster, nil)

				// Mock target cluster get
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(456), true).
					Return(targetCluster, nil)
			},
			expectError: true,
			errorMsg:    "failed to parse backup id",
		},
		{
			name: "error - snapshot mode backup query fails",
			req: &globalngv1.RestoreClusterRequest{
				SourceClusterId: "123",
				TargetClusterId: "456",
				RestoreMode:     globalngv1.RestoreMode_RESTORE_MODE_SNAPSHOT,
				BackupId:        "789",
			},
			setupMocks: func(mockClusterRepo *mockclusterrepo.MockRepo, mockBackupRepo *mockbrrepo.MockBackupRepo) {
				sourceCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      123,
						OrganizationId: 100,
					},
				}
				targetCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      456,
						OrganizationId: 200,
					},
				}

				// Mock source cluster get
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(123), true).
					Return(sourceCluster, nil)

				// Mock target cluster get
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(456), true).
					Return(targetCluster, nil)

				// Mock backup query - returns error
				mockBackupRepo.EXPECT().
					UnscopedQuery(gomock.Any(), gomock.Any(), gomock.Eq((*pagination.Page)(nil))).
					Return(nil, bizerr.New(bizerr.ErrCodeDB, "database error"))
			},
			expectError: true,
			errorMsg:    "failed to get backup",
		},
		{
			name: "error - snapshot mode backup not found",
			req: &globalngv1.RestoreClusterRequest{
				SourceClusterId: "123",
				TargetClusterId: "456",
				RestoreMode:     globalngv1.RestoreMode_RESTORE_MODE_SNAPSHOT,
				BackupId:        "789",
			},
			setupMocks: func(mockClusterRepo *mockclusterrepo.MockRepo, mockBackupRepo *mockbrrepo.MockBackupRepo) {
				sourceCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      123,
						OrganizationId: 100,
					},
				}
				targetCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      456,
						OrganizationId: 200,
					},
				}

				// Mock source cluster get
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(123), true).
					Return(sourceCluster, nil)

				// Mock target cluster get
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(456), true).
					Return(targetCluster, nil)

				// Mock backup query - returns empty result
				mockBackupRepo.EXPECT().
					UnscopedQuery(gomock.Any(), gomock.Any(), gomock.Eq((*pagination.Page)(nil))).
					Return([]*entity.Backup{}, nil)
			},
			expectError: true,
			errorMsg:    "backup not found",
		},
		{
			name: "error - snapshot mode auto backup expired",
			req: &globalngv1.RestoreClusterRequest{
				SourceClusterId: "123",
				TargetClusterId: "456",
				RestoreMode:     globalngv1.RestoreMode_RESTORE_MODE_SNAPSHOT,
				BackupId:        "789",
			},
			setupMocks: func(mockClusterRepo *mockclusterrepo.MockRepo, mockBackupRepo *mockbrrepo.MockBackupRepo) {
				sourceCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      123,
						OrganizationId: 100,
					},
				}
				targetCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      456,
						OrganizationId: 200,
					},
				}
				expiredBackup := &entity.Backup{
					Backup: &schema.Backup{
						ID:              789,
						ClusterId:       123,
						TriggerType:     schema.BackupTriggerTypeAuto,
						State:           schema.BackupStateSuccess,
						ExpirationTime:  time.Now().UTC().Add(-time.Hour),
						BackupSizeBytes: 1024 * 1024,
					},
				}

				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(123), true).
					Return(sourceCluster, nil)
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(456), true).
					Return(targetCluster, nil)
				mockBackupRepo.EXPECT().
					UnscopedQuery(gomock.Any(), gomock.Any(), gomock.Eq((*pagination.Page)(nil))).
					DoAndReturn(func(ctx context.Context, filter *br.QueryBackupsFilter, page *pagination.Page) ([]*entity.Backup, bizerr.BizError) {
						assert.Equal(t, []uint64{789}, filter.Ids)
						assert.Equal(t, ptr.Bool(false), filter.Deleted)
						return []*entity.Backup{expiredBackup}, nil
					})
			},
			expectError: true,
			errorMsg:    "backup has expired",
		},
		{
			name: "error - PITR mode missing point in time",
			req: &globalngv1.RestoreClusterRequest{
				SourceClusterId: "123",
				TargetClusterId: "456",
				RestoreMode:     globalngv1.RestoreMode_RESTORE_MODE_PITR,
				PointInTime:     nil,
			},
			setupMocks: func(mockClusterRepo *mockclusterrepo.MockRepo, mockBackupRepo *mockbrrepo.MockBackupRepo) {
				sourceCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      123,
						OrganizationId: 100,
					},
				}
				targetCluster := &entity.Cluster{
					Cluster: &globalngv1.Cluster{
						ClusterId:      456,
						OrganizationId: 200,
					},
				}

				// Mock source cluster get
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(123), true).
					Return(sourceCluster, nil)

				// Mock target cluster get
				mockClusterRepo.EXPECT().
					Get(gomock.Any(), uint64(456), true).
					Return(targetCluster, nil)
			},
			expectError: true,
			errorMsg:    "PointInTime is required for PiTR restore",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			mockClusterRepo := mockclusterrepo.NewMockRepo(ctrl)
			mockBackupRepo := mockbrrepo.NewMockBackupRepo(ctrl)

			adapter := &restoreFromPremiumAdapter{
				backupRepo:  mockBackupRepo,
				clusterRepo: mockClusterRepo,
			}

			tt.setupMocks(mockClusterRepo, mockBackupRepo)

			sourceCluster, targetCluster, backup, pointInTime, err := adapter.getRestoreContextInfo(ctx, tt.req)

			if tt.expectError {
				require.Error(t, err)
				assert.Contains(t, err.Error(), tt.errorMsg)
				assert.Nil(t, sourceCluster)
				assert.Nil(t, targetCluster)
				assert.Nil(t, backup)
				assert.Nil(t, pointInTime)
			} else {
				require.NoError(t, err)
				tt.validateResult(sourceCluster, targetCluster, backup, pointInTime)
			}
		})
	}
}

// Test edge cases and boundary conditions
func TestGetRestoreContextInfo_EdgeCases(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	ctx := t.Context()

	t.Run("snapshot mode - large backup id", func(t *testing.T) {
		mockClusterRepo := mockclusterrepo.NewMockRepo(ctrl)
		mockBackupRepo := mockbrrepo.NewMockBackupRepo(ctrl)

		adapter := &restoreFromPremiumAdapter{
			clusterRepo: mockClusterRepo,
			backupRepo:  mockBackupRepo,
		}

		req := &globalngv1.RestoreClusterRequest{
			SourceClusterId: "18446744073709551615", // Max uint64
			TargetClusterId: "1",
			RestoreMode:     globalngv1.RestoreMode_RESTORE_MODE_SNAPSHOT,
			BackupId:        "18446744073709551615", // Max uint64
		}

		sourceCluster := &entity.Cluster{
			Cluster: &globalngv1.Cluster{
				ClusterId:      18446744073709551615,
				OrganizationId: 100,
			},
		}
		targetCluster := &entity.Cluster{
			Cluster: &globalngv1.Cluster{
				ClusterId:      1,
				OrganizationId: 200,
			},
		}
		backup := &entity.Backup{
			Backup: &schema.Backup{
				ID:              18446744073709551615,
				ClusterId:       18446744073709551615,
				BackupSizeBytes: 1024 * 1024,
				State:           schema.BackupStateSuccess,
			},
		}

		// Mock source cluster get
		mockClusterRepo.EXPECT().
			Get(gomock.Any(), uint64(18446744073709551615), true).
			Return(sourceCluster, nil)

		// Mock target cluster get
		mockClusterRepo.EXPECT().
			Get(gomock.Any(), uint64(1), true).
			Return(targetCluster, nil)

		// Mock backup query
		mockBackupRepo.EXPECT().
			UnscopedQuery(gomock.Any(), gomock.Any(), gomock.Eq((*pagination.Page)(nil))).
			Return([]*entity.Backup{backup}, nil)

		sourceResult, targetResult, backupResult, pointInTime, err := adapter.getRestoreContextInfo(ctx, req)

		require.NoError(t, err)
		assert.NotNil(t, sourceResult)
		assert.NotNil(t, targetResult)
		assert.NotNil(t, backupResult)
		assert.Nil(t, pointInTime)
		assert.Equal(t, uint64(18446744073709551615), sourceResult.GetClusterId())
		assert.Equal(t, uint64(1), targetResult.GetClusterId())
		assert.Equal(t, uint64(18446744073709551615), backupResult.ID)
	})

	t.Run("PITR mode - far future point in time", func(t *testing.T) {
		mockClusterRepo := mockclusterrepo.NewMockRepo(ctrl)
		mockBackupRepo := mockbrrepo.NewMockBackupRepo(ctrl)

		adapter := &restoreFromPremiumAdapter{
			clusterRepo: mockClusterRepo,
			backupRepo:  mockBackupRepo,
		}

		farFutureTime := time.Date(2100, 12, 31, 23, 59, 59, 0, time.UTC)
		req := &globalngv1.RestoreClusterRequest{
			SourceClusterId: "123",
			TargetClusterId: "456",
			RestoreMode:     globalngv1.RestoreMode_RESTORE_MODE_PITR,
			PointInTime:     timestamppb.New(farFutureTime),
		}

		sourceCluster := &entity.Cluster{
			Cluster: &globalngv1.Cluster{
				ClusterId:      123,
				OrganizationId: 100,
			},
		}
		targetCluster := &entity.Cluster{
			Cluster: &globalngv1.Cluster{
				ClusterId:      456,
				OrganizationId: 200,
			},
		}

		// Mock source cluster get
		mockClusterRepo.EXPECT().
			Get(gomock.Any(), uint64(123), true).
			Return(sourceCluster, nil)

		// Mock target cluster get
		mockClusterRepo.EXPECT().
			Get(gomock.Any(), uint64(456), true).
			Return(targetCluster, nil)

		sourceResult, targetResult, backupResult, pointInTime, err := adapter.getRestoreContextInfo(ctx, req)

		require.NoError(t, err)
		assert.NotNil(t, sourceResult)
		assert.NotNil(t, targetResult)
		assert.Nil(t, backupResult)
		assert.NotNil(t, pointInTime)
		assert.Equal(t, farFutureTime, *pointInTime)
	})
}

func TestPremiumCreateRestore_RejectsUnrestorableSnapshotBackupBeforeWorkflow(t *testing.T) {
	tests := []struct {
		name     string
		backup   *entity.Backup
		errorMsg string
	}{
		{
			name: "failed backup",
			backup: &entity.Backup{Backup: &schema.Backup{
				ID:               789,
				ClusterId:        123,
				State:            schema.BackupStateFailed,
				KernelBackupId:   1001,
				KernelBackupName: "kernel-backup-1001",
			}},
			errorMsg: "is not restorable",
		},
		{
			name: "missing kernel backup id",
			backup: &entity.Backup{Backup: &schema.Backup{
				ID:               789,
				ClusterId:        123,
				State:            schema.BackupStateSuccess,
				KernelBackupName: "kernel-backup-1001",
			}},
			errorMsg: "missing kernel backup metadata",
		},
		{
			name: "missing kernel backup name",
			backup: &entity.Backup{Backup: &schema.Backup{
				ID:             789,
				ClusterId:      123,
				State:          schema.BackupStateSuccess,
				KernelBackupId: 1001,
			}},
			errorMsg: "missing kernel backup metadata",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctrl := gomock.NewController(t)
			mockClusterRepo := mockclusterrepo.NewMockRepo(ctrl)
			mockBackupRepo := mockbrrepo.NewMockBackupRepo(ctrl)

			adapter := &restoreFromPremiumAdapter{
				backupRepo:  mockBackupRepo,
				clusterRepo: mockClusterRepo,
			}

			mockClusterRepo.EXPECT().
				Get(gomock.Any(), uint64(123), true).
				Return(&entity.Cluster{Cluster: &globalngv1.Cluster{ClusterId: 123}}, nil)
			mockClusterRepo.EXPECT().
				Get(gomock.Any(), uint64(456), true).
				Return(&entity.Cluster{Cluster: &globalngv1.Cluster{ClusterId: 456}}, nil)
			mockBackupRepo.EXPECT().
				UnscopedQuery(gomock.Any(), gomock.Any(), gomock.Eq((*pagination.Page)(nil))).
				Return([]*entity.Backup{tt.backup}, nil)

			_, berr := adapter.PrepareRestore(t.Context(), &globalngv1.RestoreClusterRequest{
				SourceClusterId: "123",
				TargetClusterId: "456",
				RestoreMode:     globalngv1.RestoreMode_RESTORE_MODE_SNAPSHOT,
				BackupId:        "789",
			})

			require.NotNil(t, berr)
			assert.Contains(t, berr.Error(), tt.errorMsg)
		})
	}
}

func TestPremiumCreateRestore_PITRDoesNotValidateSnapshotBackup(t *testing.T) {
	ctrl := gomock.NewController(t)
	mockClusterRepo := mockclusterrepo.NewMockRepo(ctrl)
	mockBackupRepo := mockbrrepo.NewMockBackupRepo(ctrl)

	adapter := &restoreFromPremiumAdapter{
		backupRepo:  mockBackupRepo,
		clusterRepo: mockClusterRepo,
	}

	mockClusterRepo.EXPECT().
		Get(gomock.Any(), uint64(123), true).
		Return(&entity.Cluster{Cluster: &globalngv1.Cluster{ClusterId: 123}}, nil)
	mockClusterRepo.EXPECT().
		Get(gomock.Any(), uint64(456), true).
		Return(&entity.Cluster{Cluster: &globalngv1.Cluster{ClusterId: 456}}, nil)

	sourceCluster, targetCluster, backup, pointInTime, berr := adapter.getRestoreContextInfo(t.Context(), &globalngv1.RestoreClusterRequest{
		SourceClusterId: "123",
		TargetClusterId: "456",
		RestoreMode:     globalngv1.RestoreMode_RESTORE_MODE_PITR,
		PointInTime:     timestamppb.New(time.Date(2026, 7, 22, 1, 2, 3, 0, time.UTC)),
	})

	require.Nil(t, berr)
	require.NotNil(t, sourceCluster)
	require.NotNil(t, targetCluster)
	require.Nil(t, backup)
	require.NotNil(t, pointInTime)
}

func TestPremiumStopRestore_RegionalNotFoundIsIdempotentSuccess(t *testing.T) {
	ctrl := gomock.NewController(t)
	mockWorkflow := mockworkflow.NewMockWorkflow(ctrl)
	mockClusterRepo := mockclusterrepo.NewMockRepo(ctrl)
	mockRegionRepo := mockregionrepo.NewMockRepo(ctrl)
	mockRegionalCli := mockregionalserver.NewMockClient(ctrl)

	adapter := &restoreFromPremiumAdapter{
		workflow:    mockWorkflow,
		clusterRepo: mockClusterRepo,
		regionRepo:  mockRegionRepo,
		regionalCli: mockRegionalCli,
	}

	targetCluster := &entity.Cluster{
		Cluster: &globalngv1.Cluster{
			ClusterId:    456,
			SharedPoolId: "shared-pool-1",
		},
		RegionId: 42,
	}
	targetRegion := &entity.Region{RegionID: 42}

	mockWorkflow.EXPECT().
		DeleteDagInstancesWithDagId(gomock.Any(), "456", common.RestoreCluster).
		Return(nil)
	mockClusterRepo.EXPECT().
		Get(gomock.Any(), uint64(456), true).
		Return(targetCluster, nil)
	mockRegionRepo.EXPECT().
		Get(gomock.Any(), uint64(42)).
		Return(targetRegion, nil)
	mockRegionalCli.EXPECT().
		DeleteLightweightRestore(gomock.Any(), targetRegion, &clusterngv1beta.DeleteLightweightRestoreRequest{
			TargetSharedPoolId: "shared-pool-1",
			RestoreId:          "456",
		}).
		Return(bizerr.New(bizerr.ErrCodeRecordNotFound, "restore not found"))

	berr := adapter.StopRestore(t.Context(), &globalngv1.StopRestoreClusterRequest{TargetClusterId: "456"})
	require.Nil(t, berr)
}

func TestPremiumStopRestore_RegionalDeleteFailureStillPropagates(t *testing.T) {
	ctrl := gomock.NewController(t)
	mockWorkflow := mockworkflow.NewMockWorkflow(ctrl)
	mockClusterRepo := mockclusterrepo.NewMockRepo(ctrl)
	mockRegionRepo := mockregionrepo.NewMockRepo(ctrl)
	mockRegionalCli := mockregionalserver.NewMockClient(ctrl)

	adapter := &restoreFromPremiumAdapter{
		workflow:    mockWorkflow,
		clusterRepo: mockClusterRepo,
		regionRepo:  mockRegionRepo,
		regionalCli: mockRegionalCli,
	}

	targetCluster := &entity.Cluster{
		Cluster: &globalngv1.Cluster{
			ClusterId:    456,
			SharedPoolId: "shared-pool-1",
		},
		RegionId: 42,
	}
	targetRegion := &entity.Region{RegionID: 42}

	mockWorkflow.EXPECT().
		DeleteDagInstancesWithDagId(gomock.Any(), "456", common.RestoreCluster).
		Return(nil)
	mockClusterRepo.EXPECT().
		Get(gomock.Any(), uint64(456), true).
		Return(targetCluster, nil)
	mockRegionRepo.EXPECT().
		Get(gomock.Any(), uint64(42)).
		Return(targetRegion, nil)
	mockRegionalCli.EXPECT().
		DeleteLightweightRestore(gomock.Any(), targetRegion, gomock.Any()).
		Return(bizerr.New(bizerr.GeneralInternalErrorCode, "regional unavailable"))

	berr := adapter.StopRestore(t.Context(), &globalngv1.StopRestoreClusterRequest{TargetClusterId: "456"})
	require.NotNil(t, berr)
	assert.Contains(t, berr.Error(), "failed to delete lightweight restore")
}
