// Package permission provides property-based tests for permission operations.
// This file contains property tests that verify permission operations go through
// the unified Provider interface.
package permission

import (
	"context"
	"sync"
	"testing"
	"time"

	"AutoSSO/internal/config"
	"AutoSSO/internal/feishu"
	"AutoSSO/internal/pkg/logger"
	"AutoSSO/internal/provider"
	"AutoSSO/internal/state"

	"pgregory.net/rapid"
)

// Feature: autosso-refactoring, Property 6: 权限操作通过统一接口
// For any cloud platform and permission operation request, Permission_Manager
// should call the specific implementation through the Cloud_Provider interface.
//
// **Validates: Requirements 3.2, 3.3**

// mockProvider is a mock implementation of the Provider interface for testing.
// It tracks all method calls to verify that operations go through the interface.
type mockProvider struct {
	name                  string
	addPermissionCalls    []provider.PermissionRequest
	removePermissionCalls []provider.PermissionRequest
	getUserIDCalls        []string
	mu                    sync.Mutex
	shouldFail            bool
}

func newMockProvider(name string) *mockProvider {
	return &mockProvider{
		name:                  name,
		addPermissionCalls:    make([]provider.PermissionRequest, 0),
		removePermissionCalls: make([]provider.PermissionRequest, 0),
		getUserIDCalls:        make([]string, 0),
	}
}

func (m *mockProvider) Name() string {
	return m.name
}

func (m *mockProvider) AddPermission(ctx context.Context, req *provider.PermissionRequest) error {
	m.mu.Lock()
	defer m.mu.Unlock()
	if req != nil {
		m.addPermissionCalls = append(m.addPermissionCalls, *req)
	}
	if m.shouldFail {
		return context.DeadlineExceeded
	}
	return nil
}

func (m *mockProvider) RemovePermission(ctx context.Context, req *provider.PermissionRequest) error {
	m.mu.Lock()
	defer m.mu.Unlock()
	if req != nil {
		m.removePermissionCalls = append(m.removePermissionCalls, *req)
	}
	if m.shouldFail {
		return context.DeadlineExceeded
	}
	return nil
}

func (m *mockProvider) GetUserID(ctx context.Context, email string) (string, error) {
	m.mu.Lock()
	defer m.mu.Unlock()
	m.getUserIDCalls = append(m.getUserIDCalls, email)
	return "user-" + email, nil
}

func (m *mockProvider) ValidateCredentials(ctx context.Context) error {
	return nil
}

func (m *mockProvider) Close() error {
	return nil
}

func (m *mockProvider) getAddPermissionCalls() []provider.PermissionRequest {
	m.mu.Lock()
	defer m.mu.Unlock()
	result := make([]provider.PermissionRequest, len(m.addPermissionCalls))
	copy(result, m.addPermissionCalls)
	return result
}

func (m *mockProvider) getRemovePermissionCalls() []provider.PermissionRequest {
	m.mu.Lock()
	defer m.mu.Unlock()
	result := make([]provider.PermissionRequest, len(m.removePermissionCalls))
	copy(result, m.removePermissionCalls)
	return result
}

// mockStateStore is a mock implementation of the state.Store interface for testing.
type mockStateStore struct {
	pendingRemovals []*state.PendingRemoval
	mu              sync.Mutex
}

func newMockStateStore() *mockStateStore {
	return &mockStateStore{
		pendingRemovals: make([]*state.PendingRemoval, 0),
	}
}

func (s *mockStateStore) SaveInstance(ctx context.Context, instance *state.ApprovalInstance) error {
	return nil
}

func (s *mockStateStore) GetInstance(ctx context.Context, instanceID string) (*state.ApprovalInstance, error) {
	return nil, nil
}

func (s *mockStateStore) ListInstances(ctx context.Context, filter *state.InstanceFilter) ([]*state.ApprovalInstance, error) {
	return nil, nil
}

func (s *mockStateStore) DeleteInstance(ctx context.Context, instanceID string) error {
	return nil
}

func (s *mockStateStore) SavePendingRemoval(ctx context.Context, removal *state.PendingRemoval) error {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.pendingRemovals = append(s.pendingRemovals, removal)
	return nil
}

func (s *mockStateStore) GetPendingRemovals(ctx context.Context) ([]*state.PendingRemoval, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	result := make([]*state.PendingRemoval, len(s.pendingRemovals))
	copy(result, s.pendingRemovals)
	return result, nil
}

func (s *mockStateStore) DeletePendingRemoval(ctx context.Context, id int64) error {
	s.mu.Lock()
	defer s.mu.Unlock()
	for i, r := range s.pendingRemovals {
		if r.ID == id {
			s.pendingRemovals = append(s.pendingRemovals[:i], s.pendingRemovals[i+1:]...)
			break
		}
	}
	return nil
}

func (s *mockStateStore) SaveDeletedInstance(ctx context.Context, instanceID string) error {
	return nil
}

func (s *mockStateStore) IsInstanceDeleted(ctx context.Context, instanceID string) (bool, error) {
	return false, nil
}

func (s *mockStateStore) Close() error {
	return nil
}

// Generator functions for property-based testing

// genEmail generates a valid email address.
func genEmail() *rapid.Generator[string] {
	return rapid.Custom(func(t *rapid.T) string {
		user := rapid.StringMatching(`[a-z][a-z0-9]{2,10}`).Draw(t, "user")
		domain := rapid.SampledFrom([]string{"example.com", "test.org", "company.io"}).Draw(t, "domain")
		return user + "@" + domain
	})
}

// genAccountID generates a valid cloud account ID.
func genAccountID() *rapid.Generator[string] {
	return rapid.OneOf(
		// AWS-style account ID (12 digits)
		rapid.StringMatching(`[0-9]{12}`),
		// GCP-style project ID
		rapid.StringMatching(`[a-z][a-z0-9-]{5,20}`),
		// Azure-style subscription ID (UUID format)
		rapid.StringMatching(`[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}`),
		// Alibaba-style account ID (16 digits)
		rapid.StringMatching(`[0-9]{16}`),
	)
}

// genPermissionSet generates a valid permission set name.
func genPermissionSet() *rapid.Generator[string] {
	return rapid.OneOf(
		rapid.SampledFrom([]string{
			"DBaaS-Prod-ViewOnly-Role",
			"DBaaS-Prod-OnCall-Role",
			"DBaaS-Prod-Admin-Role",
			"PingCAP-SecurityAdmin-Role",
		}),
		rapid.StringMatching(`[A-Z][a-zA-Z0-9-]{5,30}-Role`),
	)
}

// genPermissionSets generates a list of permission sets.
func genPermissionSets() *rapid.Generator[[]string] {
	return rapid.SliceOfN(genPermissionSet(), 1, 5)
}

// genCloudType generates a valid cloud type.
func genCloudType() *rapid.Generator[string] {
	return rapid.SampledFrom([]string{"AWS", "GCP", "Azure", "Alibaba"})
}

// genProviderType generates a valid provider type.
func genProviderType() *rapid.Generator[provider.ProviderType] {
	return rapid.SampledFrom([]provider.ProviderType{
		provider.ProviderAWS,
		provider.ProviderGCP,
		provider.ProviderAzure,
		provider.ProviderAlibaba,
	})
}

// genApprovalData generates valid approval data for testing.
func genApprovalData(accountID string) *rapid.Generator[*feishu.ApprovalData] {
	return rapid.Custom(func(t *rapid.T) *feishu.ApprovalData {
		return &feishu.ApprovalData{
			Email:          genEmail().Draw(t, "email"),
			AppType:        true, // Must be true for valid approval data
			AccountID:      accountID,
			PermissionSets: genPermissionSets().Draw(t, "permission_sets"),
			StartTime:      time.Now(),
			EndTime:        time.Now().Add(24 * time.Hour),
			IsApproved:     true,
			IsExpired:      false,
			CloudType:      genCloudType().Draw(t, "cloud_type"),
		}
	})
}

// genPendingRemoval generates a pending removal record for testing.
func genPendingRemoval(accountID string) *rapid.Generator[*state.PendingRemoval] {
	return rapid.Custom(func(t *rapid.T) *state.PendingRemoval {
		return &state.PendingRemoval{
			ID:            rapid.Int64Range(1, 10000).Draw(t, "id"),
			AccountID:     accountID,
			Email:         genEmail().Draw(t, "email"),
			PermissionSet: genPermissionSet().Draw(t, "permission_set"),
			CloudType:     genCloudType().Draw(t, "cloud_type"),
			ExpiredAt:     time.Now().Add(-24 * time.Hour),
			ScheduledAt:   time.Now().Add(-1 * time.Hour),
		}
	})
}

// createTestManager creates a Manager with mock providers for testing.
func createTestManager(providerType provider.ProviderType, accountID string, mockProv *mockProvider) (*Manager, error) {
	// Create config with the account mapped to the provider type
	cfg := &config.Config{
		Providers: config.ProvidersConfig{},
		Runtime: config.RuntimeConfig{
			GracePeriodDays: 3,
		},
	}

	// Add account to the appropriate provider config
	account := config.CloudAccount{ID: accountID, Name: "test-account", Type: "prod"}
	switch providerType {
	case provider.ProviderAWS:
		cfg.Providers.AWS.Accounts = []config.CloudAccount{account}
	case provider.ProviderGCP:
		cfg.Providers.GCP.Projects = []config.CloudAccount{account}
	case provider.ProviderAzure:
		cfg.Providers.Azure.Subscriptions = []config.CloudAccount{account}
	case provider.ProviderAlibaba:
		cfg.Providers.Alibaba.Accounts = []config.CloudAccount{account}
	}

	// Create registry and register the mock provider
	registry, err := provider.NewRegistry(cfg)
	if err != nil {
		return nil, err
	}

	if err := registry.RegisterProvider(providerType, mockProv); err != nil {
		return nil, err
	}

	// Create logger
	log := logger.NewLogger(logger.Config{Level: logger.ErrorLevel})

	// Create state store
	stateStore := newMockStateStore()

	// Create manager without Feishu client (not needed for this test)
	manager := NewManager(registry, nil, stateStore, cfg, log)

	return manager, nil
}

// TestAddPermissionsThroughProviderInterface tests that AddPermissions calls
// the Provider.AddPermission method for each permission set.
//
// Feature: autosso-refactoring, Property 6: 权限操作通过统一接口
// **Validates: Requirements 3.2**
func TestAddPermissionsThroughProviderInterface(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate random provider type and account ID
		providerType := genProviderType().Draw(rt, "provider_type")
		accountID := genAccountID().Draw(rt, "account_id")

		// Create mock provider
		mockProv := newMockProvider(string(providerType))

		// Create manager with mock provider
		manager, err := createTestManager(providerType, accountID, mockProv)
		if err != nil {
			rt.Fatalf("Failed to create test manager: %v", err)
		}

		// Generate approval data
		approvalData := genApprovalData(accountID).Draw(rt, "approval_data")

		// Call AddPermissions
		ctx := context.Background()
		err = manager.AddPermissions(ctx, approvalData)
		if err != nil {
			rt.Fatalf("AddPermissions failed: %v", err)
		}

		// Verify that AddPermission was called through the Provider interface
		calls := mockProv.getAddPermissionCalls()
		if len(calls) != len(approvalData.PermissionSets) {
			rt.Fatalf("Expected %d AddPermission calls, got %d",
				len(approvalData.PermissionSets), len(calls))
		}

		// Verify each call has the correct parameters
		for i, call := range calls {
			if call.AccountID != accountID {
				rt.Fatalf("Call %d: expected AccountID %q, got %q", i, accountID, call.AccountID)
			}
			if call.UserEmail != approvalData.Email {
				rt.Fatalf("Call %d: expected UserEmail %q, got %q", i, approvalData.Email, call.UserEmail)
			}
			if len(call.PermissionSets) != 1 {
				rt.Fatalf("Call %d: expected 1 permission set, got %d", i, len(call.PermissionSets))
			}
		}
	})
}

// TestRemovePermissionsThroughProviderInterface tests that RemovePermissions calls
// the Provider.RemovePermission method.
//
// Feature: autosso-refactoring, Property 6: 权限操作通过统一接口
// **Validates: Requirements 3.3**
func TestRemovePermissionsThroughProviderInterface(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate random provider type and account ID
		providerType := genProviderType().Draw(rt, "provider_type")
		accountID := genAccountID().Draw(rt, "account_id")

		// Create mock provider
		mockProv := newMockProvider(string(providerType))

		// Create manager with mock provider
		manager, err := createTestManager(providerType, accountID, mockProv)
		if err != nil {
			rt.Fatalf("Failed to create test manager: %v", err)
		}

		// Generate pending removal
		pendingRemoval := genPendingRemoval(accountID).Draw(rt, "pending_removal")

		// Call RemovePermissions
		ctx := context.Background()
		err = manager.RemovePermissions(ctx, pendingRemoval)
		if err != nil {
			rt.Fatalf("RemovePermissions failed: %v", err)
		}

		// Verify that RemovePermission was called through the Provider interface
		calls := mockProv.getRemovePermissionCalls()
		if len(calls) != 1 {
			rt.Fatalf("Expected 1 RemovePermission call, got %d", len(calls))
		}

		// Verify the call has the correct parameters
		call := calls[0]
		if call.AccountID != accountID {
			rt.Fatalf("Expected AccountID %q, got %q", accountID, call.AccountID)
		}
		if call.UserEmail != pendingRemoval.Email {
			rt.Fatalf("Expected UserEmail %q, got %q", pendingRemoval.Email, call.UserEmail)
		}
		if len(call.PermissionSets) != 1 || call.PermissionSets[0] != pendingRemoval.PermissionSet {
			rt.Fatalf("Expected PermissionSets [%q], got %v",
				pendingRemoval.PermissionSet, call.PermissionSets)
		}
	})
}

// TestAllCloudPlatformsUseProviderInterface tests that all cloud platform types
// (AWS, GCP, Azure, Alibaba) use the Provider interface for permission operations.
//
// Feature: autosso-refactoring, Property 6: 权限操作通过统一接口
// **Validates: Requirements 3.2, 3.3**
func TestAllCloudPlatformsUseProviderInterface(t *testing.T) {
	providerTypes := []provider.ProviderType{
		provider.ProviderAWS,
		provider.ProviderGCP,
		provider.ProviderAzure,
		provider.ProviderAlibaba,
	}

	for _, providerType := range providerTypes {
		t.Run(string(providerType), func(t *testing.T) {
			rapid.Check(t, func(rt *rapid.T) {
				accountID := genAccountID().Draw(rt, "account_id")

				// Create mock provider
				mockProv := newMockProvider(string(providerType))

				// Create manager with mock provider
				manager, err := createTestManager(providerType, accountID, mockProv)
				if err != nil {
					rt.Fatalf("Failed to create test manager: %v", err)
				}

				// Test AddPermissions
				approvalData := genApprovalData(accountID).Draw(rt, "approval_data")
				ctx := context.Background()

				err = manager.AddPermissions(ctx, approvalData)
				if err != nil {
					rt.Fatalf("AddPermissions failed for %s: %v", providerType, err)
				}

				addCalls := mockProv.getAddPermissionCalls()
				if len(addCalls) == 0 {
					rt.Fatalf("No AddPermission calls made for %s", providerType)
				}

				// Test RemovePermissions
				pendingRemoval := genPendingRemoval(accountID).Draw(rt, "pending_removal")

				err = manager.RemovePermissions(ctx, pendingRemoval)
				if err != nil {
					rt.Fatalf("RemovePermissions failed for %s: %v", providerType, err)
				}

				removeCalls := mockProv.getRemovePermissionCalls()
				if len(removeCalls) == 0 {
					rt.Fatalf("No RemovePermission calls made for %s", providerType)
				}
			})
		})
	}
}

// TestProviderInterfaceIsOnlyWayToInteractWithCloudPlatforms tests that the
// Provider interface is the only way to interact with cloud platforms.
// This is verified by ensuring that all permission operations go through
// the registered provider in the registry.
//
// Feature: autosso-refactoring, Property 6: 权限操作通过统一接口
// **Validates: Requirements 3.2, 3.3**
func TestProviderInterfaceIsOnlyWayToInteractWithCloudPlatforms(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate multiple accounts for different providers
		awsAccountID := rapid.StringMatching(`[0-9]{12}`).Draw(rt, "aws_account_id")
		gcpProjectID := rapid.StringMatching(`[a-z][a-z0-9-]{5,20}`).Draw(rt, "gcp_project_id")
		azureSubID := rapid.StringMatching(`[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}`).Draw(rt, "azure_sub_id")
		alibabaAccountID := rapid.StringMatching(`[0-9]{16}`).Draw(rt, "alibaba_account_id")

		// Create config with all providers
		cfg := &config.Config{
			Providers: config.ProvidersConfig{
				AWS:     config.AWSConfig{Accounts: []config.CloudAccount{{ID: awsAccountID}}},
				GCP:     config.GCPConfig{Projects: []config.CloudAccount{{ID: gcpProjectID}}},
				Azure:   config.AzureConfig{Subscriptions: []config.CloudAccount{{ID: azureSubID}}},
				Alibaba: config.AlibabaConfig{Accounts: []config.CloudAccount{{ID: alibabaAccountID}}},
			},
			Runtime: config.RuntimeConfig{GracePeriodDays: 3},
		}

		// Create registry
		registry, err := provider.NewRegistry(cfg)
		if err != nil {
			rt.Fatalf("Failed to create registry: %v", err)
		}

		// Create mock providers for each type
		awsMock := newMockProvider("AWS")
		gcpMock := newMockProvider("GCP")
		azureMock := newMockProvider("Azure")
		alibabaMock := newMockProvider("Alibaba")

		// Register all mock providers
		_ = registry.RegisterProvider(provider.ProviderAWS, awsMock)
		_ = registry.RegisterProvider(provider.ProviderGCP, gcpMock)
		_ = registry.RegisterProvider(provider.ProviderAzure, azureMock)
		_ = registry.RegisterProvider(provider.ProviderAlibaba, alibabaMock)

		// Create manager
		log := logger.NewLogger(logger.Config{Level: logger.ErrorLevel})
		stateStore := newMockStateStore()
		manager := NewManager(registry, nil, stateStore, cfg, log)

		ctx := context.Background()

		// Test that AWS operations go through AWS provider
		awsData := &feishu.ApprovalData{
			Email: "test@example.com", AppType: true, AccountID: awsAccountID,
			PermissionSets: []string{"TestRole"}, CloudType: "AWS",
			StartTime: time.Now(), EndTime: time.Now().Add(24 * time.Hour),
		}
		_ = manager.AddPermissions(ctx, awsData)
		if len(awsMock.getAddPermissionCalls()) == 0 {
			rt.Fatal("AWS AddPermission not called through provider interface")
		}

		// Test that GCP operations go through GCP provider
		gcpData := &feishu.ApprovalData{
			Email: "test@example.com", AppType: true, AccountID: gcpProjectID,
			PermissionSets: []string{"TestRole"}, CloudType: "GCP",
			StartTime: time.Now(), EndTime: time.Now().Add(24 * time.Hour),
		}
		_ = manager.AddPermissions(ctx, gcpData)
		if len(gcpMock.getAddPermissionCalls()) == 0 {
			rt.Fatal("GCP AddPermission not called through provider interface")
		}

		// Test that Azure operations go through Azure provider
		azureData := &feishu.ApprovalData{
			Email: "test@example.com", AppType: true, AccountID: azureSubID,
			PermissionSets: []string{"TestRole"}, CloudType: "Azure",
			StartTime: time.Now(), EndTime: time.Now().Add(24 * time.Hour),
		}
		_ = manager.AddPermissions(ctx, azureData)
		if len(azureMock.getAddPermissionCalls()) == 0 {
			rt.Fatal("Azure AddPermission not called through provider interface")
		}

		// Test that Alibaba operations go through Alibaba provider
		alibabaData := &feishu.ApprovalData{
			Email: "test@example.com", AppType: true, AccountID: alibabaAccountID,
			PermissionSets: []string{"TestRole"}, CloudType: "Alibaba",
			StartTime: time.Now(), EndTime: time.Now().Add(24 * time.Hour),
		}
		_ = manager.AddPermissions(ctx, alibabaData)
		if len(alibabaMock.getAddPermissionCalls()) == 0 {
			rt.Fatal("Alibaba AddPermission not called through provider interface")
		}
	})
}

// TestPermissionRequestParametersPassedCorrectly tests that permission request
// parameters are correctly passed to the Provider interface methods.
//
// Feature: autosso-refactoring, Property 6: 权限操作通过统一接口
// **Validates: Requirements 3.2, 3.3**
func TestPermissionRequestParametersPassedCorrectly(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		providerType := genProviderType().Draw(rt, "provider_type")
		accountID := genAccountID().Draw(rt, "account_id")
		email := genEmail().Draw(rt, "email")
		permissionSets := genPermissionSets().Draw(rt, "permission_sets")

		// Create mock provider
		mockProv := newMockProvider(string(providerType))

		// Create manager
		manager, err := createTestManager(providerType, accountID, mockProv)
		if err != nil {
			rt.Fatalf("Failed to create test manager: %v", err)
		}

		// Create approval data with specific values
		approvalData := &feishu.ApprovalData{
			Email:          email,
			AppType:        true,
			AccountID:      accountID,
			PermissionSets: permissionSets,
			StartTime:      time.Now(),
			EndTime:        time.Now().Add(24 * time.Hour),
			IsApproved:     true,
			IsExpired:      false,
			CloudType:      string(providerType),
		}

		// Call AddPermissions
		ctx := context.Background()
		err = manager.AddPermissions(ctx, approvalData)
		if err != nil {
			rt.Fatalf("AddPermissions failed: %v", err)
		}

		// Verify all parameters were passed correctly
		calls := mockProv.getAddPermissionCalls()
		if len(calls) != len(permissionSets) {
			rt.Fatalf("Expected %d calls, got %d", len(permissionSets), len(calls))
		}

		// Collect all permission sets from calls
		calledPermissions := make(map[string]bool)
		for _, call := range calls {
			// Verify account ID
			if call.AccountID != accountID {
				rt.Fatalf("AccountID mismatch: expected %q, got %q", accountID, call.AccountID)
			}
			// Verify email
			if call.UserEmail != email {
				rt.Fatalf("UserEmail mismatch: expected %q, got %q", email, call.UserEmail)
			}
			// Collect permission sets
			for _, ps := range call.PermissionSets {
				calledPermissions[ps] = true
			}
		}

		// Verify all permission sets were included
		for _, ps := range permissionSets {
			if !calledPermissions[ps] {
				rt.Fatalf("Permission set %q was not passed to provider", ps)
			}
		}
	})
}

// TestMultiplePermissionSetsCallProviderMultipleTimes tests that when multiple
// permission sets are requested, the Provider interface is called for each one.
//
// Feature: autosso-refactoring, Property 6: 权限操作通过统一接口
// **Validates: Requirements 3.2**
func TestMultiplePermissionSetsCallProviderMultipleTimes(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		providerType := genProviderType().Draw(rt, "provider_type")
		accountID := genAccountID().Draw(rt, "account_id")

		// Generate multiple unique permission sets
		numPermissions := rapid.IntRange(1, 5).Draw(rt, "num_permissions")
		permissionSets := make([]string, numPermissions)
		for i := 0; i < numPermissions; i++ {
			permissionSets[i] = genPermissionSet().Draw(rt, "permission_set")
		}

		// Create mock provider
		mockProv := newMockProvider(string(providerType))

		// Create manager
		manager, err := createTestManager(providerType, accountID, mockProv)
		if err != nil {
			rt.Fatalf("Failed to create test manager: %v", err)
		}

		// Create approval data
		approvalData := &feishu.ApprovalData{
			Email:          genEmail().Draw(rt, "email"),
			AppType:        true,
			AccountID:      accountID,
			PermissionSets: permissionSets,
			StartTime:      time.Now(),
			EndTime:        time.Now().Add(24 * time.Hour),
			IsApproved:     true,
			CloudType:      string(providerType),
		}

		// Call AddPermissions
		ctx := context.Background()
		err = manager.AddPermissions(ctx, approvalData)
		if err != nil {
			rt.Fatalf("AddPermissions failed: %v", err)
		}

		// Verify the provider was called the correct number of times
		calls := mockProv.getAddPermissionCalls()
		if len(calls) != numPermissions {
			rt.Fatalf("Expected %d AddPermission calls, got %d", numPermissions, len(calls))
		}
	})
}

// TestRemovePermissionCallsProviderOnce tests that RemovePermissions calls
// the Provider interface exactly once per pending removal.
//
// Feature: autosso-refactoring, Property 6: 权限操作通过统一接口
// **Validates: Requirements 3.3**
func TestRemovePermissionCallsProviderOnce(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		providerType := genProviderType().Draw(rt, "provider_type")
		accountID := genAccountID().Draw(rt, "account_id")

		// Create mock provider
		mockProv := newMockProvider(string(providerType))

		// Create manager
		manager, err := createTestManager(providerType, accountID, mockProv)
		if err != nil {
			rt.Fatalf("Failed to create test manager: %v", err)
		}

		// Create pending removal
		pendingRemoval := genPendingRemoval(accountID).Draw(rt, "pending_removal")

		// Call RemovePermissions
		ctx := context.Background()
		err = manager.RemovePermissions(ctx, pendingRemoval)
		if err != nil {
			rt.Fatalf("RemovePermissions failed: %v", err)
		}

		// Verify the provider was called exactly once
		calls := mockProv.getRemovePermissionCalls()
		if len(calls) != 1 {
			rt.Fatalf("Expected exactly 1 RemovePermission call, got %d", len(calls))
		}
	})
}
