package backup

import (
	"context"
	"errors"
	"testing"

	"github.com/stretchr/testify/mock"
	"github.com/tidbcloud/observability/vmbackupmanager/pkg/config"
)

func TestMigrateNeeded(t *testing.T) {
	tests := []struct {
		name        string
		config      config.Config
		mockFiles   map[string]bool
		mockError   error
		expected    bool
		expectError bool
	}{
		{
			name: "migrate flag not set",
			config: config.Config{
				Migrate: false,
			},
			expected:    false,
			expectError: false,
		},
		{
			name: "latest folder exists",
			config: config.Config{
				Migrate: true,
			},
			mockFiles: map[string]bool{
				IncrementalBackupPath: true,
			},
			expected:    false,
			expectError: false,
		},
		{
			name: "storage error checking latest",
			config: config.Config{
				Migrate: true,
			},
			mockError:   errors.New("storage error"),
			expected:    false,
			expectError: true,
		},
		{
			name: "missing data file",
			config: config.Config{
				Migrate: true,
			},
			mockFiles: map[string]bool{
				IncrementalBackupPath: false,
				"data":                false,
				"indexdb":             true,
				"metadata":            true,
			},
			expected:    false,
			expectError: false,
		},
		{
			name: "missing indexdb file",
			config: config.Config{
				Migrate: true,
			},
			mockFiles: map[string]bool{
				IncrementalBackupPath: false,
				"data":                true,
				"indexdb":             false,
				"metadata":            true,
			},
			expected:    false,
			expectError: false,
		},
		{
			name: "missing metadata file",
			config: config.Config{
				Migrate: true,
			},
			mockFiles: map[string]bool{
				IncrementalBackupPath: false,
				"data":                true,
				"indexdb":             true,
				"metadata":            false,
			},
			expected:    false,
			expectError: false,
		},
		{
			name: "storage error checking data",
			config: config.Config{
				Migrate: true,
			},
			mockFiles: map[string]bool{
				IncrementalBackupPath: false,
			},
			mockError:   errors.New("storage error"),
			expected:    false,
			expectError: true,
		},
		{
			name: "all files exist, migration needed",
			config: config.Config{
				Migrate: true,
			},
			mockFiles: map[string]bool{
				IncrementalBackupPath: false,
				"data":                true,
				"indexdb":             true,
				"metadata":            true,
			},
			expected:    true,
			expectError: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			mockStore := NewMockStorage()

			// Setup mock expectations based on test case
			if !tt.config.Migrate {
				// When migrate flag is not set, no storage calls should be made
				// Don't set up any mock expectations
			} else if tt.mockError != nil {
				// For error cases, mock the first call that would fail
				mockStore.On("Exists", mock.Anything, mock.AnythingOfType("string")).Return(false, tt.mockError)
			} else {
				// For success cases, setup expectations for each file check
				for path, exists := range tt.mockFiles {
					mockStore.On("Exists", mock.Anything, path).Return(exists, nil)
				}
				// If no specific files are set, mock any call to return false
				if len(tt.mockFiles) == 0 {
					mockStore.On("Exists", mock.Anything, mock.AnythingOfType("string")).Return(false, nil)
				}
			}

			manager := &Manager{
				config: &tt.config,
				store:  mockStore,
				ctx:    context.Background(),
			}

			result, err := manager.migrateNeeded()

			// Check error expectations
			if (err != nil) != tt.expectError {
				t.Errorf("migrateNeeded() error = %v, expectError %v", err, tt.expectError)
				return
			}

			// Check result
			if result != tt.expected {
				t.Errorf("migrateNeeded() = %v, expected %v", result, tt.expected)
			}

			// Verify mock expectations were met
			mockStore.AssertExpectations(t)
		})
	}
}
