// Package config provides configuration management for AutoSSO.
// This file contains property-based tests for permission name mapping correctness.
package config

import (
	"testing"

	"pgregory.net/rapid"
)

// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// For any Feishu permission name, querying through configuration mapping
// should return the correct actual permission name.
//
// **Validates: Requirements 9.6**

// GetRealPermissionName looks up the real permission name for a given Feishu permission name.
// If the Feishu name is not found in the mappings, it returns the original name (passthrough).
// This implements the expected behavior for permission name resolution.
func (c *Config) GetRealPermissionName(feishuName string) string {
	for _, mapping := range c.PermissionMappings {
		if mapping.FeishuName == feishuName {
			return mapping.RealName
		}
	}
	// Passthrough: return the original name if not found
	return feishuName
}

// GetGCPRoles looks up the GCP IAM roles for a given custom role name.
// If the custom role is not found in the mappings, it returns nil.
// This replaces the Read_ini_value function from gcp_custom_role_control.go.
//
// Requirements: 9.6, 10.4
func (c *Config) GetGCPRoles(customRole string) []string {
	for _, mapping := range c.GCPRoleMappings {
		if mapping.CustomRole == customRole {
			// Return a copy to prevent modification of the original slice
			result := make([]string, len(mapping.GCPRoles))
			copy(result, mapping.GCPRoles)
			return result
		}
	}
	return nil
}

// GetAzureRoleSuffix looks up the role suffix for a given Azure subscription name.
// If the subscription is not found, it returns an empty string.
// This replaces the Azure_Convert_Role_Name function from azure_role_manage.go.
//
// Requirements: 9.6
func (c *Config) GetAzureRoleSuffix(subscriptionName string) string {
	for _, sub := range c.Providers.Azure.Subscriptions {
		if sub.Name == subscriptionName {
			return sub.RoleSuffix
		}
	}
	return ""
}

// GetAzureSubscriptionID looks up the subscription ID for a given Azure subscription name.
// If the subscription is not found, it returns an empty string.
// This replaces the Azure_Convert_subid function from azure_role_manage.go.
//
// Requirements: 9.6
func (c *Config) GetAzureSubscriptionID(subscriptionName string) string {
	for _, sub := range c.Providers.Azure.Subscriptions {
		if sub.Name == subscriptionName {
			return sub.ID
		}
	}
	return ""
}

// genUniqueFeishuName generates a unique Feishu permission name.
func genUniqueFeishuName() *rapid.Generator[string] {
	return rapid.StringMatching(`[a-z][a-z0-9_-]{2,20}`)
}

// genRealPermissionName generates a real permission name (typically more descriptive).
func genRealPermissionName() *rapid.Generator[string] {
	return rapid.StringMatching(`[A-Z][a-zA-Z0-9-]{5,40}`)
}

// genUniquePermissionMapping generates a valid PermissionMapping with unique names.
func genUniquePermissionMapping() *rapid.Generator[PermissionMapping] {
	return rapid.Custom(func(t *rapid.T) PermissionMapping {
		return PermissionMapping{
			FeishuName: genUniqueFeishuName().Draw(t, "feishu_name"),
			RealName:   genRealPermissionName().Draw(t, "real_name"),
		}
	})
}

// genUniquePermissionMappings generates a slice of PermissionMappings with unique FeishuNames.
func genUniquePermissionMappings() *rapid.Generator[[]PermissionMapping] {
	return rapid.Custom(func(t *rapid.T) []PermissionMapping {
		count := rapid.IntRange(1, 20).Draw(t, "mapping_count")
		mappings := make([]PermissionMapping, 0, count)
		usedNames := make(map[string]bool)

		for i := 0; i < count; i++ {
			// Generate unique FeishuName
			var feishuName string
			for {
				feishuName = genUniqueFeishuName().Draw(t, "feishu_name")
				if !usedNames[feishuName] {
					usedNames[feishuName] = true
					break
				}
			}

			mappings = append(mappings, PermissionMapping{
				FeishuName: feishuName,
				RealName:   genRealPermissionName().Draw(t, "real_name"),
			})
		}

		return mappings
	})
}

// TestPermissionMappingCorrectness tests that for any Feishu permission name
// in the configuration mapping, querying returns the correct real permission name.
//
// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// **Validates: Requirements 9.6**
func TestPermissionMappingCorrectness(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate random permission mappings
		mappings := genUniquePermissionMappings().Draw(rt, "mappings")

		// Create a Config with the permission mappings
		cfg := &Config{
			PermissionMappings: mappings,
		}

		// For each mapping, verify that looking up the FeishuName returns the correct RealName
		for _, mapping := range mappings {
			result := cfg.GetRealPermissionName(mapping.FeishuName)
			if result != mapping.RealName {
				rt.Fatalf("Permission mapping lookup failed for FeishuName %q:\n"+
					"Expected RealName: %q\n"+
					"Got: %q",
					mapping.FeishuName, mapping.RealName, result)
			}
		}
	})
}

// TestPermissionMappingPassthrough tests that unmapped permission names
// return themselves (passthrough behavior).
//
// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// **Validates: Requirements 9.6**
func TestPermissionMappingPassthrough(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate random permission mappings
		mappings := genUniquePermissionMappings().Draw(rt, "mappings")

		// Create a Config with the permission mappings
		cfg := &Config{
			PermissionMappings: mappings,
		}

		// Generate a name that is NOT in the mappings
		unmappedName := genUniqueFeishuName().Draw(rt, "unmapped_name")

		// Ensure the name is not in the mappings
		for _, mapping := range mappings {
			if mapping.FeishuName == unmappedName {
				// Skip this iteration if we accidentally generated a mapped name
				return
			}
		}

		// Verify that looking up an unmapped name returns itself
		result := cfg.GetRealPermissionName(unmappedName)
		if result != unmappedName {
			rt.Fatalf("Passthrough failed for unmapped name %q:\n"+
				"Expected: %q (same as input)\n"+
				"Got: %q",
				unmappedName, unmappedName, result)
		}
	})
}

// TestPermissionMappingEmptyConfig tests that with no mappings configured,
// all names pass through unchanged.
//
// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// **Validates: Requirements 9.6**
func TestPermissionMappingEmptyConfig(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Create a Config with no permission mappings
		cfg := &Config{
			PermissionMappings: []PermissionMapping{},
		}

		// Generate a random permission name
		permName := genUniqueFeishuName().Draw(rt, "perm_name")

		// Verify that looking up any name returns itself
		result := cfg.GetRealPermissionName(permName)
		if result != permName {
			rt.Fatalf("Empty config passthrough failed for name %q:\n"+
				"Expected: %q (same as input)\n"+
				"Got: %q",
				permName, permName, result)
		}
	})
}

// TestPermissionMappingNilConfig tests that with nil mappings,
// all names pass through unchanged.
//
// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// **Validates: Requirements 9.6**
func TestPermissionMappingNilConfig(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Create a Config with nil permission mappings
		cfg := &Config{
			PermissionMappings: nil,
		}

		// Generate a random permission name
		permName := genUniqueFeishuName().Draw(rt, "perm_name")

		// Verify that looking up any name returns itself
		result := cfg.GetRealPermissionName(permName)
		if result != permName {
			rt.Fatalf("Nil config passthrough failed for name %q:\n"+
				"Expected: %q (same as input)\n"+
				"Got: %q",
				permName, permName, result)
		}
	})
}

// TestPermissionMappingFirstMatchWins tests that when there are duplicate
// FeishuNames (which shouldn't happen in practice), the first match is returned.
// This tests the implementation behavior for edge cases.
//
// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// **Validates: Requirements 9.6**
func TestPermissionMappingFirstMatchWins(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate a common FeishuName
		commonFeishuName := genUniqueFeishuName().Draw(rt, "common_feishu_name")

		// Generate two different RealNames
		firstRealName := genRealPermissionName().Draw(rt, "first_real_name")
		secondRealName := genRealPermissionName().Draw(rt, "second_real_name")

		// Ensure they are different
		if firstRealName == secondRealName {
			secondRealName = secondRealName + "-different"
		}

		// Create mappings with duplicate FeishuName
		mappings := []PermissionMapping{
			{FeishuName: commonFeishuName, RealName: firstRealName},
			{FeishuName: commonFeishuName, RealName: secondRealName},
		}

		cfg := &Config{
			PermissionMappings: mappings,
		}

		// Verify that the first match is returned
		result := cfg.GetRealPermissionName(commonFeishuName)
		if result != firstRealName {
			rt.Fatalf("First match wins failed for FeishuName %q:\n"+
				"Expected (first match): %q\n"+
				"Got: %q",
				commonFeishuName, firstRealName, result)
		}
	})
}

// TestPermissionMappingCaseSensitivity tests that permission name lookup
// is case-sensitive.
//
// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// **Validates: Requirements 9.6**
func TestPermissionMappingCaseSensitivity(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate a FeishuName with lowercase
		feishuName := genUniqueFeishuName().Draw(rt, "feishu_name")
		realName := genRealPermissionName().Draw(rt, "real_name")

		// Create a Config with the mapping
		cfg := &Config{
			PermissionMappings: []PermissionMapping{
				{FeishuName: feishuName, RealName: realName},
			},
		}

		// Verify exact match works
		result := cfg.GetRealPermissionName(feishuName)
		if result != realName {
			rt.Fatalf("Exact match failed for FeishuName %q:\n"+
				"Expected: %q\n"+
				"Got: %q",
				feishuName, realName, result)
		}

		// Create an uppercase version of the name
		upperFeishuName := ""
		for _, c := range feishuName {
			if c >= 'a' && c <= 'z' {
				upperFeishuName += string(c - 32) // Convert to uppercase
			} else {
				upperFeishuName += string(c)
			}
		}

		// If the uppercase version is different, verify it doesn't match
		if upperFeishuName != feishuName {
			upperResult := cfg.GetRealPermissionName(upperFeishuName)
			// Should return the input itself (passthrough) since it doesn't match
			if upperResult != upperFeishuName {
				rt.Fatalf("Case sensitivity failed: uppercase %q should not match lowercase %q\n"+
					"Expected (passthrough): %q\n"+
					"Got: %q",
					upperFeishuName, feishuName, upperFeishuName, upperResult)
			}
		}
	})
}

// TestPermissionMappingExtensibility tests that the permission mapping table
// is extensible - new mappings can be added without affecting existing ones.
//
// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// **Validates: Requirements 9.6**
func TestPermissionMappingExtensibility(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate initial mappings
		initialMappings := genUniquePermissionMappings().Draw(rt, "initial_mappings")

		// Generate a new mapping that doesn't conflict with existing ones
		newFeishuName := genUniqueFeishuName().Draw(rt, "new_feishu_name")
		newRealName := genRealPermissionName().Draw(rt, "new_real_name")

		// Ensure the new name doesn't conflict
		for _, mapping := range initialMappings {
			if mapping.FeishuName == newFeishuName {
				newFeishuName = newFeishuName + "-new"
				break
			}
		}

		// Create config with initial mappings
		cfg := &Config{
			PermissionMappings: initialMappings,
		}

		// Verify initial mappings work
		for _, mapping := range initialMappings {
			result := cfg.GetRealPermissionName(mapping.FeishuName)
			if result != mapping.RealName {
				rt.Fatalf("Initial mapping lookup failed for %q", mapping.FeishuName)
			}
		}

		// Add new mapping (simulating extensibility)
		cfg.PermissionMappings = append(cfg.PermissionMappings, PermissionMapping{
			FeishuName: newFeishuName,
			RealName:   newRealName,
		})

		// Verify all initial mappings still work
		for _, mapping := range initialMappings {
			result := cfg.GetRealPermissionName(mapping.FeishuName)
			if result != mapping.RealName {
				rt.Fatalf("Initial mapping broken after extension for %q:\n"+
					"Expected: %q\n"+
					"Got: %q",
					mapping.FeishuName, mapping.RealName, result)
			}
		}

		// Verify new mapping works
		result := cfg.GetRealPermissionName(newFeishuName)
		if result != newRealName {
			rt.Fatalf("New mapping lookup failed for %q:\n"+
				"Expected: %q\n"+
				"Got: %q",
				newFeishuName, newRealName, result)
		}
	})
}


// =============================================================================
// GCP Role Mapping Tests
// =============================================================================

// genGCPCustomRoleName generates a custom role name for GCP.
func genGCPCustomRoleName() *rapid.Generator[string] {
	return rapid.StringMatching(`[A-Z][a-zA-Z0-9-]{5,30}-Role`)
}

// genGCPIAMRole generates a GCP IAM role name.
func genGCPIAMRole() *rapid.Generator[string] {
	return rapid.StringMatching(`roles/[a-z][a-zA-Z0-9.]{3,30}`)
}

// genGCPRoleMapping generates a valid GCPRoleMapping.
func genGCPRoleMapping() *rapid.Generator[GCPRoleMapping] {
	return rapid.Custom(func(t *rapid.T) GCPRoleMapping {
		numRoles := rapid.IntRange(1, 5).Draw(t, "num_roles")
		roles := make([]string, numRoles)
		for i := 0; i < numRoles; i++ {
			roles[i] = genGCPIAMRole().Draw(t, "gcp_role")
		}
		return GCPRoleMapping{
			CustomRole: genGCPCustomRoleName().Draw(t, "custom_role"),
			GCPRoles:   roles,
		}
	})
}

// genUniqueGCPRoleMappings generates a slice of GCPRoleMappings with unique CustomRoles.
func genUniqueGCPRoleMappings() *rapid.Generator[[]GCPRoleMapping] {
	return rapid.Custom(func(t *rapid.T) []GCPRoleMapping {
		count := rapid.IntRange(1, 10).Draw(t, "mapping_count")
		mappings := make([]GCPRoleMapping, 0, count)
		usedNames := make(map[string]bool)

		for i := 0; i < count; i++ {
			var customRole string
			for {
				customRole = genGCPCustomRoleName().Draw(t, "custom_role")
				if !usedNames[customRole] {
					usedNames[customRole] = true
					break
				}
			}

			numRoles := rapid.IntRange(1, 5).Draw(t, "num_roles")
			roles := make([]string, numRoles)
			for j := 0; j < numRoles; j++ {
				roles[j] = genGCPIAMRole().Draw(t, "gcp_role")
			}

			mappings = append(mappings, GCPRoleMapping{
				CustomRole: customRole,
				GCPRoles:   roles,
			})
		}

		return mappings
	})
}

// TestGCPRoleMappingCorrectness tests that for any custom role name
// in the configuration mapping, querying returns the correct GCP IAM roles.
//
// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// **Validates: Requirements 9.6, 10.4**
func TestGCPRoleMappingCorrectness(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate random GCP role mappings
		mappings := genUniqueGCPRoleMappings().Draw(rt, "mappings")

		// Create a Config with the GCP role mappings
		cfg := &Config{
			GCPRoleMappings: mappings,
		}

		// For each mapping, verify that looking up the CustomRole returns the correct GCPRoles
		for _, mapping := range mappings {
			result := cfg.GetGCPRoles(mapping.CustomRole)
			if len(result) != len(mapping.GCPRoles) {
				rt.Fatalf("GCP role mapping lookup failed for CustomRole %q:\n"+
					"Expected %d roles, got %d roles",
					mapping.CustomRole, len(mapping.GCPRoles), len(result))
			}
			for i, role := range mapping.GCPRoles {
				if result[i] != role {
					rt.Fatalf("GCP role mapping lookup failed for CustomRole %q:\n"+
						"Expected role[%d]: %q\n"+
						"Got: %q",
						mapping.CustomRole, i, role, result[i])
				}
			}
		}
	})
}

// TestGCPRoleMappingNotFound tests that unmapped custom roles return nil.
//
// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// **Validates: Requirements 9.6, 10.4**
func TestGCPRoleMappingNotFound(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate random GCP role mappings
		mappings := genUniqueGCPRoleMappings().Draw(rt, "mappings")

		// Create a Config with the GCP role mappings
		cfg := &Config{
			GCPRoleMappings: mappings,
		}

		// Generate a name that is NOT in the mappings
		unmappedName := genGCPCustomRoleName().Draw(rt, "unmapped_name")

		// Ensure the name is not in the mappings
		for _, mapping := range mappings {
			if mapping.CustomRole == unmappedName {
				// Skip this iteration if we accidentally generated a mapped name
				return
			}
		}

		// Verify that looking up an unmapped name returns nil
		result := cfg.GetGCPRoles(unmappedName)
		if result != nil {
			rt.Fatalf("GCP role mapping should return nil for unmapped name %q:\n"+
				"Got: %v",
				unmappedName, result)
		}
	})
}

// TestGCPRoleMappingEmptyConfig tests that with no mappings configured,
// all lookups return nil.
//
// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// **Validates: Requirements 9.6, 10.4**
func TestGCPRoleMappingEmptyConfig(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Create a Config with no GCP role mappings
		cfg := &Config{
			GCPRoleMappings: []GCPRoleMapping{},
		}

		// Generate a random custom role name
		customRole := genGCPCustomRoleName().Draw(rt, "custom_role")

		// Verify that looking up any name returns nil
		result := cfg.GetGCPRoles(customRole)
		if result != nil {
			rt.Fatalf("Empty config should return nil for name %q:\n"+
				"Got: %v",
				customRole, result)
		}
	})
}

// TestGCPRoleMappingReturnsCopy tests that the returned slice is a copy,
// not a reference to the original.
//
// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// **Validates: Requirements 9.6, 10.4**
func TestGCPRoleMappingReturnsCopy(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate a GCP role mapping
		mapping := genGCPRoleMapping().Draw(rt, "mapping")

		// Create a Config with the mapping
		cfg := &Config{
			GCPRoleMappings: []GCPRoleMapping{mapping},
		}

		// Get the roles
		result := cfg.GetGCPRoles(mapping.CustomRole)
		if result == nil {
			rt.Fatalf("Expected non-nil result for CustomRole %q", mapping.CustomRole)
		}

		// Modify the result
		if len(result) > 0 {
			originalFirst := result[0]
			result[0] = "modified-role"

			// Verify the original is unchanged
			result2 := cfg.GetGCPRoles(mapping.CustomRole)
			if result2[0] != originalFirst {
				rt.Fatalf("Modifying returned slice affected original:\n"+
					"Expected: %q\n"+
					"Got: %q",
					originalFirst, result2[0])
			}
		}
	})
}

// =============================================================================
// Azure Role Suffix Mapping Tests
// =============================================================================

// genAzureSubscriptionName generates an Azure subscription name.
func genAzureSubscriptionName() *rapid.Generator[string] {
	return rapid.StringMatching(`[a-z][a-z0-9-]{5,30}`)
}

// genAzureSubscriptionID generates an Azure subscription ID (UUID format).
func genAzureSubscriptionID() *rapid.Generator[string] {
	return rapid.StringMatching(`[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}`)
}

// genAzureRoleSuffix generates an Azure role suffix.
func genAzureRoleSuffix() *rapid.Generator[string] {
	return rapid.OneOf(
		rapid.Just(""),
		rapid.StringMatching(`-[a-z0-9]{1,10}`),
	)
}

// genAzureSubscription generates a valid CloudAccount for Azure.
func genAzureSubscription() *rapid.Generator[CloudAccount] {
	return rapid.Custom(func(t *rapid.T) CloudAccount {
		return CloudAccount{
			ID:         genAzureSubscriptionID().Draw(t, "id"),
			Name:       genAzureSubscriptionName().Draw(t, "name"),
			Type:       rapid.SampledFrom([]string{"prod", "dev", "test"}).Draw(t, "type"),
			RoleSuffix: genAzureRoleSuffix().Draw(t, "role_suffix"),
		}
	})
}

// genUniqueAzureSubscriptions generates a slice of CloudAccounts with unique names.
func genUniqueAzureSubscriptions() *rapid.Generator[[]CloudAccount] {
	return rapid.Custom(func(t *rapid.T) []CloudAccount {
		count := rapid.IntRange(1, 10).Draw(t, "subscription_count")
		subscriptions := make([]CloudAccount, 0, count)
		usedNames := make(map[string]bool)

		for i := 0; i < count; i++ {
			var name string
			for {
				name = genAzureSubscriptionName().Draw(t, "name")
				if !usedNames[name] {
					usedNames[name] = true
					break
				}
			}

			subscriptions = append(subscriptions, CloudAccount{
				ID:         genAzureSubscriptionID().Draw(t, "id"),
				Name:       name,
				Type:       rapid.SampledFrom([]string{"prod", "dev", "test"}).Draw(t, "type"),
				RoleSuffix: genAzureRoleSuffix().Draw(t, "role_suffix"),
			})
		}

		return subscriptions
	})
}

// TestAzureRoleSuffixMappingCorrectness tests that for any Azure subscription name
// in the configuration, querying returns the correct role suffix.
//
// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// **Validates: Requirements 9.6**
func TestAzureRoleSuffixMappingCorrectness(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate random Azure subscriptions
		subscriptions := genUniqueAzureSubscriptions().Draw(rt, "subscriptions")

		// Create a Config with the Azure subscriptions
		cfg := &Config{
			Providers: ProvidersConfig{
				Azure: AzureConfig{
					Subscriptions: subscriptions,
				},
			},
		}

		// For each subscription, verify that looking up the name returns the correct role suffix
		for _, sub := range subscriptions {
			result := cfg.GetAzureRoleSuffix(sub.Name)
			if result != sub.RoleSuffix {
				rt.Fatalf("Azure role suffix lookup failed for subscription %q:\n"+
					"Expected: %q\n"+
					"Got: %q",
					sub.Name, sub.RoleSuffix, result)
			}
		}
	})
}

// TestAzureSubscriptionIDMappingCorrectness tests that for any Azure subscription name
// in the configuration, querying returns the correct subscription ID.
//
// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// **Validates: Requirements 9.6**
func TestAzureSubscriptionIDMappingCorrectness(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate random Azure subscriptions
		subscriptions := genUniqueAzureSubscriptions().Draw(rt, "subscriptions")

		// Create a Config with the Azure subscriptions
		cfg := &Config{
			Providers: ProvidersConfig{
				Azure: AzureConfig{
					Subscriptions: subscriptions,
				},
			},
		}

		// For each subscription, verify that looking up the name returns the correct ID
		for _, sub := range subscriptions {
			result := cfg.GetAzureSubscriptionID(sub.Name)
			if result != sub.ID {
				rt.Fatalf("Azure subscription ID lookup failed for subscription %q:\n"+
					"Expected: %q\n"+
					"Got: %q",
					sub.Name, sub.ID, result)
			}
		}
	})
}

// TestAzureRoleSuffixNotFound tests that unmapped subscription names return empty string.
//
// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// **Validates: Requirements 9.6**
func TestAzureRoleSuffixNotFound(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Generate random Azure subscriptions
		subscriptions := genUniqueAzureSubscriptions().Draw(rt, "subscriptions")

		// Create a Config with the Azure subscriptions
		cfg := &Config{
			Providers: ProvidersConfig{
				Azure: AzureConfig{
					Subscriptions: subscriptions,
				},
			},
		}

		// Generate a name that is NOT in the subscriptions
		unmappedName := genAzureSubscriptionName().Draw(rt, "unmapped_name")

		// Ensure the name is not in the subscriptions
		for _, sub := range subscriptions {
			if sub.Name == unmappedName {
				// Skip this iteration if we accidentally generated a mapped name
				return
			}
		}

		// Verify that looking up an unmapped name returns empty string
		result := cfg.GetAzureRoleSuffix(unmappedName)
		if result != "" {
			rt.Fatalf("Azure role suffix should return empty string for unmapped name %q:\n"+
				"Got: %q",
				unmappedName, result)
		}

		// Also verify subscription ID lookup returns empty string
		idResult := cfg.GetAzureSubscriptionID(unmappedName)
		if idResult != "" {
			rt.Fatalf("Azure subscription ID should return empty string for unmapped name %q:\n"+
				"Got: %q",
				unmappedName, idResult)
		}
	})
}

// TestAzureRoleSuffixEmptyConfig tests that with no subscriptions configured,
// all lookups return empty string.
//
// Feature: autosso-refactoring, Property 5: 权限名称映射正确性
// **Validates: Requirements 9.6**
func TestAzureRoleSuffixEmptyConfig(t *testing.T) {
	rapid.Check(t, func(rt *rapid.T) {
		// Create a Config with no Azure subscriptions
		cfg := &Config{
			Providers: ProvidersConfig{
				Azure: AzureConfig{
					Subscriptions: []CloudAccount{},
				},
			},
		}

		// Generate a random subscription name
		subName := genAzureSubscriptionName().Draw(rt, "sub_name")

		// Verify that looking up any name returns empty string
		result := cfg.GetAzureRoleSuffix(subName)
		if result != "" {
			rt.Fatalf("Empty config should return empty string for name %q:\n"+
				"Got: %q",
				subName, result)
		}
	})
}
