package globalservice

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/tidbcloud/observability/pkg/common/constants"
	"github.com/tidbcloud/observability/pkg/globalservice/structs"
)

func TestLogicalRegionRouter(t *testing.T) {
	// Create test metadata with logical region routes
	testMeta := &structs.GlobalServiceMeta{
		Vendors: map[constants.ProvidedVendor][]structs.RegionInfo{
			constants.AWS: {
				{
					Region: "us-west-1",
					Routers: []structs.RegionalRouter{
						{
							DnsAddress:        "http://us-west-1-logical-1.example.com",
							Primary:           true,
							LogicalRegionName: "logical-region-1",
						},
						{
							DnsAddress:        "http://us-west-1-logical-2.example.com",
							Primary:           false,
							LogicalRegionName: "logical-region-2",
						},
					},
				},
			},
		},
		Routes: structs.RouteTable{
			"aws-us-west-1": {
				"tidbcloud:1372813089209216864:.*": "logical-region-1",
				"byoc:1234567890123456789:.*":      "logical-region-2",
				"tidbcloud:.*:app-specific-123":    "logical-region-1",
				".*byoc:.*":                        "logical-region-2",
				".*":                               "logical-region-1", // default fallback
			},
		},
	}

	// Create mock meta cache getter
	mockMetaGetter := &mockMetaCacheGetter{
		meta: testMeta,
	}

	// Create logical region router
	router := NewLogicalRegionRouter(mockMetaGetter)
	// Simulate what GlobalManager does - build pattern caches when routes are loaded
	router.BuildPatternCache(testMeta.Routes)

	t.Run("IsLogicalRegionEnabled", func(t *testing.T) {
		assert.True(t, router.IsLogicalRegionEnabled())
	})

	t.Run("GetLogicalRegionName_ExactMatch", func(t *testing.T) {
		ctx := context.Background()
		routingCtx := structs.RoutingContext{
			Vendor:   constants.AWS,
			Region:   "us-west-1",
			BizType:  "tidbcloud",
			TenantID: "1372813089209216864",
		}

		logicalRegion, err := router.GetLogicalRegionName(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "logical-region-1", logicalRegion)
	})

	t.Run("GetLogicalRegionName_ApplicationSpecificMatch", func(t *testing.T) {
		ctx := context.Background()
		routingCtx := structs.RoutingContext{
			Vendor:        constants.AWS,
			Region:        "us-west-1",
			BizType:       "tidbcloud",
			TenantID:      "9999999999999999999",
			ApplicationID: "app-specific-123",
		}

		logicalRegion, err := router.GetLogicalRegionName(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "logical-region-1", logicalRegion)
	})

	t.Run("GetLogicalRegionName_FallbackMatch", func(t *testing.T) {
		ctx := context.Background()
		routingCtx := structs.RoutingContext{
			Vendor:   constants.AWS,
			Region:   "us-west-1",
			BizType:  "unknown",
			TenantID: "unknown-tenant",
		}

		logicalRegion, err := router.GetLogicalRegionName(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "logical-region-1", logicalRegion)
	})

	t.Run("GetLogicalRegionRouteAddress", func(t *testing.T) {
		ctx := context.Background()
		routingCtx := structs.RoutingContext{
			Vendor:   constants.AWS,
			Region:   "us-west-1",
			BizType:  "tidbcloud",
			TenantID: "1372813089209216864",
		}

		routeAddress, err := router.GetLogicalRegionRouteInfo(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "http://us-west-1-logical-1.example.com", routeAddress.DnsAddress)
	})

	t.Run("GetLogicalRegionRouteAddress_byocTenant", func(t *testing.T) {
		ctx := context.Background()
		routingCtx := structs.RoutingContext{
			Vendor:   constants.AWS,
			Region:   "us-west-1",
			BizType:  "byoc",
			TenantID: "1234567890123456789",
		}

		routeAddress, err := router.GetLogicalRegionRouteInfo(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "http://us-west-1-logical-2.example.com", routeAddress.DnsAddress)
	})

	t.Run("GetLogicalRegionRouteAddress_byocTenant", func(t *testing.T) {
		ctx := context.Background()
		routingCtx := structs.RoutingContext{
			Vendor:   constants.AWS,
			Region:   "us-west-1",
			BizType:  "dev-byoc",
			TenantID: "1234567890123456789",
		}

		routeAddress, err := router.GetLogicalRegionRouteInfo(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "http://us-west-1-logical-2.example.com", routeAddress.DnsAddress)
	})

	t.Run("GetLogicalRegionRouteAddress_VendorNotFound", func(t *testing.T) {
		ctx := context.Background()
		routingCtx := structs.RoutingContext{
			Vendor:   "unknown",
			Region:   "us-west-1",
			BizType:  "tidbcloud",
			TenantID: "1372813089209216864",
		}

		_, err := router.GetLogicalRegionRouteInfo(ctx, routingCtx)
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "no logical region routes found for region us-west-1")
	})

	t.Run("GetLogicalRegionName_DirectLogicalRegion", func(t *testing.T) {
		// When LogicalRegion is already set (e.g. from X-Logical-Region header),
		// it should be returned immediately without any route-table lookup.
		ctx := context.Background()
		routingCtx := structs.RoutingContext{
			// No Vendor/Region/BizType/TenantID - only LogicalRegion
			LogicalRegion: "logical-region-1",
		}

		logicalRegion, err := router.GetLogicalRegionName(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "logical-region-1", logicalRegion)
	})

	t.Run("GetLogicalRegionRouteInfo_DirectLogicalRegion_NoVendor", func(t *testing.T) {
		// When only X-Logical-Region is set (Kong plugin path: no vendor/region),
		// GetLogicalRegionRouteInfo should scan all vendors and find the router.
		ctx := context.Background()
		routingCtx := structs.RoutingContext{
			LogicalRegion: "logical-region-2",
			// Vendor and Region intentionally empty
		}

		routeInfo, err := router.GetLogicalRegionRouteInfo(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "http://us-west-1-logical-2.example.com", routeInfo.DnsAddress)
	})

	t.Run("GetLogicalRegionRouteInfo_DirectLogicalRegion_UnknownName", func(t *testing.T) {
		ctx := context.Background()
		routingCtx := structs.RoutingContext{
			LogicalRegion: "nonexistent-region",
		}

		_, err := router.GetLogicalRegionRouteInfo(ctx, routingCtx)
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "no route address found for logical region nonexistent-region")
	})
}

func TestLogicalRegionRouter_Disabled(t *testing.T) {
	// Create metadata without logical region routes
	testMeta := &structs.GlobalServiceMeta{
		Vendors: map[constants.ProvidedVendor][]structs.RegionInfo{
			constants.AWS: {
				{
					Region: "us-west-1",
					Routers: []structs.RegionalRouter{
						{
							DnsAddress: "http://us-west-1.example.com",
							Primary:    true,
						},
					},
				},
			},
		},
		// No Routes defined - logical region routing disabled
	}

	mockMetaGetter := &mockMetaCacheGetter{
		meta: testMeta,
	}

	router := NewLogicalRegionRouter(mockMetaGetter)
	// No routes to build - simulates disabled logical region routing
	router.BuildPatternCache(nil)

	t.Run("IsLogicalRegionEnabled_Disabled", func(t *testing.T) {
		assert.False(t, router.IsLogicalRegionEnabled())
	})
}

// mockMetaCacheGetter is a test implementation of MetaCacheGetter
type mockMetaCacheGetter struct {
	meta *structs.GlobalServiceMeta
}

func (m *mockMetaCacheGetter) GetGlobalMetaCache() *structs.GlobalServiceMeta {
	return m.meta
}

func TestRoutingContext_BuildBizRouteKey(t *testing.T) {
	tests := []struct {
		name     string
		ctx      structs.RoutingContext
		expected string
	}{
		{
			name: "full 4-segment key",
			ctx: structs.RoutingContext{
				BizType:       "dev-devtier",
				TenantID:      "1372813089209216864",
				ProjectID:     "f02",
				ApplicationID: "devtier-infra",
			},
			expected: "dev-devtier:1372813089209216864:f02:devtier-infra",
		},
		{
			name: "no applicationID fills wildcard",
			ctx: structs.RoutingContext{
				BizType:   "tidbcloud",
				TenantID:  "1372813089209216864",
				ProjectID: "f02",
			},
			expected: "tidbcloud:1372813089209216864:f02:.*",
		},
		{
			name: "no projectID fills wildcard",
			ctx: structs.RoutingContext{
				BizType:       "tidbcloud",
				TenantID:      "1372813089209216864",
				ApplicationID: "app-123",
			},
			expected: "tidbcloud:1372813089209216864:.*:app-123",
		},
		{
			name: "no projectID and no applicationID",
			ctx: structs.RoutingContext{
				BizType:  "tidbcloud",
				TenantID: "1372813089209216864",
			},
			expected: "tidbcloud:1372813089209216864:.*:.*",
		},
		{
			name: "only bizType",
			ctx: structs.RoutingContext{
				BizType: "dev-devtier",
			},
			expected: "dev-devtier::.*:.*",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			assert.Equal(t, tt.expected, tt.ctx.BuildBizRouteKey())
		})
	}
}

func TestNormalizeRoutePattern(t *testing.T) {
	tests := []struct {
		name     string
		pattern  string
		expected string
	}{
		{
			name:     "3-segment upgraded with wildcard projectID",
			pattern:  "dev-devtier:.*:.*",
			expected: "dev-devtier:.*:.*:.*",
		},
		{
			name:     "3-segment with specific app",
			pattern:  "tidbcloud:123:app-abc",
			expected: "tidbcloud:123:.*:app-abc",
		},
		{
			name:     "4-segment unchanged",
			pattern:  "dev-devtier:.*:f02:.*",
			expected: "dev-devtier:.*:f02:.*",
		},
		{
			name:     "2-segment unchanged",
			pattern:  ".*byoc:.*",
			expected: ".*byoc:.*",
		},
		{
			name:     "single segment unchanged",
			pattern:  ".*",
			expected: ".*",
		},
		{
			name:     "5-segment unchanged",
			pattern:  "a:b:c:d:e",
			expected: "a:b:c:d:e",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			assert.Equal(t, tt.expected, normalizeRoutePattern(tt.pattern))
		})
	}
}

func TestLogicalRegionRouter_IsLogicalRegionEnabled(t *testing.T) {
	tests := []struct {
		name     string
		routes   structs.RouteTable
		expected bool
	}{
		{
			name:     "enabled with routes",
			routes:   structs.RouteTable{"aws-us-west-1": {"tidbcloud:123:.*": "logical-1"}},
			expected: true,
		},
		{
			name:     "disabled with empty routes",
			routes:   structs.RouteTable{},
			expected: false,
		},
		{
			name:     "disabled with nil routes",
			routes:   nil,
			expected: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			mockGetter := &mockMetaCacheGetter{
				meta: &structs.GlobalServiceMeta{
					Routes: tt.routes,
				},
			}
			router := NewLogicalRegionRouter(mockGetter)
			router.BuildPatternCache(tt.routes)
			assert.Equal(t, tt.expected, router.IsLogicalRegionEnabled())
		})
	}
}

func TestLogicalRegionRouter_IsLogicalRegionEnabled_NilSafety(t *testing.T) {
	t.Run("nil receiver", func(t *testing.T) {
		var router *logicalRegionRouter
		assert.False(t, router.IsLogicalRegionEnabled())
	})

	t.Run("nil metaGetter", func(t *testing.T) {
		router := &logicalRegionRouter{metaGetter: nil}
		assert.False(t, router.IsLogicalRegionEnabled())
	})

	t.Run("nil meta cache", func(t *testing.T) {
		mockGetter := &mockMetaCacheGetter{meta: nil}
		router := NewLogicalRegionRouter(mockGetter)
		router.BuildPatternCache(nil) // Simulate empty routes
		assert.False(t, router.IsLogicalRegionEnabled())
	})
}

func TestLogicalRegionRouter_PatternSpecificity(t *testing.T) {
	// Test pattern specificity calculation and sorting
	testMeta := &structs.GlobalServiceMeta{
		Vendors: map[constants.ProvidedVendor][]structs.RegionInfo{
			constants.AWS: {
				{
					Region: "us-west-1",
					Routers: []structs.RegionalRouter{
						{
							DnsAddress:        "http://us-west-1-logical-1.example.com",
							Primary:           true,
							LogicalRegionName: "logical-region-1",
						},
						{
							DnsAddress:        "http://us-west-1-logical-2.example.com",
							Primary:           false,
							LogicalRegionName: "logical-region-2",
						},
					},
				},
			},
		},
		Routes: structs.RouteTable{
			"aws-us-west-1": {
				// These patterns should be sorted by specificity (most specific first)
				".*":                                    "logical-region-1",   // least specific (score: 1)
				"tidbcloud:.*:.*":                       "logical-region-2",   // more specific (score: 13)
				"tidbcloud:1372813089209216864:.*":      "logical-region-1",   // most specific (score: 23)
				"tidbcloud:1372813089209216864:app-123": "exact-match-region", // exact match, handled separately
			},
		},
	}

	mockMetaGetter := &mockMetaCacheGetter{meta: testMeta}
	router := NewLogicalRegionRouter(mockMetaGetter)
	// Build pattern caches to test the specificity sorting
	router.BuildPatternCache(testMeta.Routes)

	ctx := context.Background()
	routingCtx := structs.RoutingContext{
		Vendor:        constants.AWS,
		Region:        "us-west-1",
		BizType:       "tidbcloud",
		TenantID:      "1372813089209216864",
		ApplicationID: "app-456", // Different app, should match tenant-level pattern
	}

	// Should match "tidbcloud:1372813089209216864:.*" (most specific wildcard pattern)
	logicalRegion, err := router.GetLogicalRegionName(ctx, routingCtx)
	assert.NoError(t, err)
	assert.Equal(t, "logical-region-1", logicalRegion)

	// Test with different tenant to ensure specificity ordering
	routingCtx.TenantID = "different-tenant"
	logicalRegion, err = router.GetLogicalRegionName(ctx, routingCtx)
	assert.NoError(t, err)
	assert.Equal(t, "logical-region-2", logicalRegion) // Should match "tidbcloud:.*:.*"
}

func TestLogicalRegionRouter_BuildPatternCache(t *testing.T) {
	// Test building pattern caches with various patterns
	routes := structs.RouteTable{
		"aws-us-west-1": {
			"tidbcloud:tenant1:.*": "logical-region-1",
			"tidbcloud:.*:.*":      "logical-region-2",
			".*":                   "logical-region-3",
			"exact:match:app":      "exact-region",      // exact match, should be skipped
			"invalid:pattern":      "should-be-ignored", // invalid pattern, should be ignored
		},
		"aws-us-east-1": {
			"byoc:.*:.*": "logical-region-4",
		},
	}

	// Mock meta with routes so IsLogicalRegionEnabled() returns true
	mockMetaGetter := &mockMetaCacheGetter{
		meta: &structs.GlobalServiceMeta{
			Routes: routes,
			Vendors: map[constants.ProvidedVendor][]structs.RegionInfo{
				constants.AWS: {
					{
						Region: "us-west-1",
						Routers: []structs.RegionalRouter{
							{DnsAddress: "http://test.com", Primary: true},
						},
					},
					{
						Region: "us-east-1",
						Routers: []structs.RegionalRouter{
							{DnsAddress: "http://test2.com", Primary: true},
						},
					},
				},
			},
		},
	}
	router := NewLogicalRegionRouter(mockMetaGetter)

	// Test initial build
	router.BuildPatternCache(routes)

	// Verify patterns were cached correctly by testing pattern matching
	ctx := context.Background()

	// Test us-west-1 specificity ordering
	routingCtx := structs.RoutingContext{
		Vendor:        constants.AWS,
		Region:        "us-west-1",
		BizType:       "tidbcloud",
		TenantID:      "tenant1",
		ApplicationID: "some-app",
	}

	logicalRegion, err := router.GetLogicalRegionName(ctx, routingCtx)
	assert.NoError(t, err)
	assert.Equal(t, "logical-region-1", logicalRegion) // Should match most specific pattern

	// Test us-east-1
	routingCtx.Region = "us-east-1"
	routingCtx.BizType = "byoc"
	routingCtx.TenantID = "any-tenant"

	logicalRegion, err = router.GetLogicalRegionName(ctx, routingCtx)
	assert.NoError(t, err)
	assert.Equal(t, "logical-region-4", logicalRegion)

	// Test building with new routes (simulates configuration update)
	newRoutes := structs.RouteTable{
		"aws-us-west-1": {
			"new:pattern:.*": "new-logical-region",
		},
	}

	// Update the mock meta to have new routes
	mockMetaGetter.meta.Routes = newRoutes
	router.BuildPatternCache(newRoutes)

	// Verify old patterns are cleared and new ones work
	routingCtx.Region = "us-west-1"
	routingCtx.BizType = "new"
	routingCtx.TenantID = "pattern"
	routingCtx.ApplicationID = "test"

	logicalRegion, err = router.GetLogicalRegionName(ctx, routingCtx)
	assert.NoError(t, err)
	assert.Equal(t, "new-logical-region", logicalRegion)
}

// TestLogicalRegionRouter_FourSegmentRouting covers the 4-segment route key
// (bizType:tenantID:projectID:applicationID) including the serverless split
// scenario described in the migration plan.
func TestLogicalRegionRouter_FourSegmentRouting(t *testing.T) {
	testMeta := &structs.GlobalServiceMeta{
		Vendors: map[constants.ProvidedVendor][]structs.RegionInfo{
			constants.AWS: {
				{
					Region: "us-east-1",
					Routers: []structs.RegionalRouter{
						{DnsAddress: "http://us-east-1-old.example.com", Primary: true, LogicalRegionName: "us-east-1-serverless"},
						{DnsAddress: "http://us-east-1-new.example.com", LogicalRegionName: "us-east-1-serverless-2"},
						{DnsAddress: "http://us-east-1-dedicated.example.com", LogicalRegionName: "us-east-1"},
					},
				},
			},
		},
		Routes: structs.RouteTable{
			"aws-us-east-1": {
				// New 4-segment patterns: project-level split (highest specificity)
				"dev-devtier:.*:f02:.*": "us-east-1-serverless-2",
				"dev-devtier:.*:f03:.*": "us-east-1-serverless-2",
				"dev-devtier:.*:f04:.*": "us-east-1-serverless-2",
				"dev-devtier:.*:f05:.*": "us-east-1-serverless-2",
				"dev-devtier:.*:f06:.*": "us-east-1-serverless-2",
				// Legacy 3-segment pattern (auto-upgraded to 4 segments at build time)
				"dev-devtier:.*:.*": "us-east-1-serverless",
				".*nextgen:.*:.*":   "us-east-1-premium",
				".*":                "us-east-1",
			},
		},
	}

	mockMetaGetter := &mockMetaCacheGetter{meta: testMeta}
	router := NewLogicalRegionRouter(mockMetaGetter)
	router.BuildPatternCache(testMeta.Routes)

	ctx := context.Background()

	t.Run("project_f02_routes_to_new_cluster", func(t *testing.T) {
		routingCtx := structs.RoutingContext{
			Vendor:    constants.AWS,
			Region:    "us-east-1",
			BizType:   "dev-devtier",
			ProjectID: "f02",
		}
		routeInfo, err := router.GetLogicalRegionRouteInfo(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "us-east-1-serverless-2", routeInfo.LogicalRegionName)
	})

	t.Run("project_f06_routes_to_new_cluster", func(t *testing.T) {
		routingCtx := structs.RoutingContext{
			Vendor:    constants.AWS,
			Region:    "us-east-1",
			BizType:   "dev-devtier",
			ProjectID: "f06",
		}
		routeInfo, err := router.GetLogicalRegionRouteInfo(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "us-east-1-serverless-2", routeInfo.LogicalRegionName)
	})

	t.Run("project_f01_falls_back_to_old_cluster", func(t *testing.T) {
		routingCtx := structs.RoutingContext{
			Vendor:    constants.AWS,
			Region:    "us-east-1",
			BizType:   "dev-devtier",
			ProjectID: "f01",
		}
		routeInfo, err := router.GetLogicalRegionRouteInfo(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "us-east-1-serverless", routeInfo.LogicalRegionName)
	})

	t.Run("no_project_falls_back_to_old_cluster", func(t *testing.T) {
		routingCtx := structs.RoutingContext{
			Vendor:  constants.AWS,
			Region:  "us-east-1",
			BizType: "dev-devtier",
		}
		routeInfo, err := router.GetLogicalRegionRouteInfo(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "us-east-1-serverless", routeInfo.LogicalRegionName)
	})

	t.Run("dedicated_falls_back_to_default", func(t *testing.T) {
		routingCtx := structs.RoutingContext{
			Vendor:  constants.AWS,
			Region:  "us-east-1",
			BizType: "tidbcloud",
		}
		routeInfo, err := router.GetLogicalRegionRouteInfo(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "us-east-1", routeInfo.LogicalRegionName)
	})

	t.Run("application_specific_overrides_project", func(t *testing.T) {
		// When applicationID is set it participates in the key but the project
		// pattern still matches because .* is used for app in the route table.
		routingCtx := structs.RoutingContext{
			Vendor:        constants.AWS,
			Region:        "us-east-1",
			BizType:       "dev-devtier",
			ProjectID:     "f02",
			ApplicationID: "devtier-infra",
		}
		routeInfo, err := router.GetLogicalRegionRouteInfo(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "us-east-1-serverless-2", routeInfo.LogicalRegionName)
	})

	t.Run("exact_4segment_pattern_match", func(t *testing.T) {
		// Exact 4-segment pattern should match via exactMatchCache.
		// devtier-infra is the fixed applicationID for all serverless parent clusters.
		exactMeta := &structs.GlobalServiceMeta{
			Vendors: testMeta.Vendors,
			Routes: structs.RouteTable{
				"aws-us-east-1": {
					"dev-devtier:.*:.*:devtier-infra": "us-east-1-serverless-2",
					".*":                              "us-east-1",
				},
			},
		}
		r := NewLogicalRegionRouter(&mockMetaCacheGetter{meta: exactMeta})
		r.BuildPatternCache(exactMeta.Routes)

		routingCtx := structs.RoutingContext{
			Vendor:        constants.AWS,
			Region:        "us-east-1",
			BizType:       "dev-devtier",
			ProjectID:     "f07",
			ApplicationID: "devtier-infra",
		}
		routeInfo, err := r.GetLogicalRegionRouteInfo(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "us-east-1-serverless-2", routeInfo.LogicalRegionName)
	})
}

// TestLogicalRegionRouter_LegacyBackwardCompat verifies that legacy 3-segment
// patterns continue to work after the 4-segment key migration.
func TestLogicalRegionRouter_LegacyBackwardCompat(t *testing.T) {
	testMeta := &structs.GlobalServiceMeta{
		Vendors: map[constants.ProvidedVendor][]structs.RegionInfo{
			constants.AWS: {
				{
					Region: "us-west-1",
					Routers: []structs.RegionalRouter{
						{DnsAddress: "http://logical-1.example.com", Primary: true, LogicalRegionName: "logical-region-1"},
						{DnsAddress: "http://logical-2.example.com", LogicalRegionName: "logical-region-2"},
					},
				},
			},
		},
		// All legacy 3-segment patterns — no projectID segment
		Routes: structs.RouteTable{
			"aws-us-west-1": {
				"tidbcloud:1372813089209216864:.*": "logical-region-1",
				"byoc:1234567890123456789:.*":      "logical-region-2",
				".*byoc:.*":                        "logical-region-2",
				".*":                               "logical-region-1",
			},
		},
	}

	mockMetaGetter := &mockMetaCacheGetter{meta: testMeta}
	router := NewLogicalRegionRouter(mockMetaGetter)
	router.BuildPatternCache(testMeta.Routes)

	ctx := context.Background()

	t.Run("legacy tenant pattern still matches", func(t *testing.T) {
		routingCtx := structs.RoutingContext{
			Vendor:   constants.AWS,
			Region:   "us-west-1",
			BizType:  "tidbcloud",
			TenantID: "1372813089209216864",
		}
		logicalRegion, err := router.GetLogicalRegionName(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "logical-region-1", logicalRegion)
	})

	t.Run("legacy byoc prefix pattern still matches", func(t *testing.T) {
		routingCtx := structs.RoutingContext{
			Vendor:   constants.AWS,
			Region:   "us-west-1",
			BizType:  "dev-byoc",
			TenantID: "1234567890123456789",
		}
		logicalRegion, err := router.GetLogicalRegionName(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "logical-region-2", logicalRegion)
	})

	t.Run("legacy fallback still matches", func(t *testing.T) {
		routingCtx := structs.RoutingContext{
			Vendor:   constants.AWS,
			Region:   "us-west-1",
			BizType:  "unknown",
			TenantID: "unknown-tenant",
		}
		logicalRegion, err := router.GetLogicalRegionName(ctx, routingCtx)
		assert.NoError(t, err)
		assert.Equal(t, "logical-region-1", logicalRegion)
	})
}

// TestPatternOrderIndependence verifies that the order of patterns in the
// route table JSON does not affect routing results.
//
// Go maps have randomized iteration order, and BuildPatternCache sorts by
// specificity — so whether ".*" is declared first or last in meta.json,
// the more specific patterns always take precedence.
func TestPatternOrderIndependence(t *testing.T) {
	// Same patterns as the dev meta.json aws-us-east-1 routes.
	// Go map iteration is randomized, so this inherently tests order independence.
	routes := structs.RouteTable{
		"aws-us-east-1": {
			".*":                              "us-east-1",
			".*nextgen:.*:.*":                 "us-east-1-nextgen",
			"dev-devtier:.*:us-east-1-f01:.*": "us-east-1-serverless",
			"dev-devtier:.*:us-east-1-f02:.*": "us-east-1-serverless-2",
			"dev-devtier:.*:us-east-1-f06:.*": "us-east-1-serverless-2",
		},
	}

	mockMetaGetter := &mockMetaCacheGetter{
		meta: &structs.GlobalServiceMeta{
			Vendors: map[constants.ProvidedVendor][]structs.RegionInfo{
				constants.AWS: {{
					Region: "us-east-1",
					Routers: []structs.RegionalRouter{
						{DnsAddress: "http://default:8080", LogicalRegionName: "us-east-1", Primary: true},
						{DnsAddress: "http://sl:8080", LogicalRegionName: "us-east-1-serverless"},
						{DnsAddress: "http://sl2:8080", LogicalRegionName: "us-east-1-serverless-2"},
						{DnsAddress: "http://ng:8080", LogicalRegionName: "us-east-1-nextgen"},
					},
				}},
			},
			Routes: routes,
		},
	}

	// Run BuildPatternCache + route resolution multiple times.
	// Each run has randomized map iteration during cache build.
	// Results must be identical every time.
	cases := []struct {
		name       string
		routingCtx structs.RoutingContext
		wantRegion string
	}{
		{
			name:       "dedicated hits catch-all despite .* being in map",
			routingCtx: structs.RoutingContext{Vendor: constants.AWS, Region: "us-east-1", BizType: "tidbcloud", TenantID: "999"},
			wantRegion: "us-east-1",
		},
		{
			name:       "serverless f02 wins over catch-all",
			routingCtx: structs.RoutingContext{Vendor: constants.AWS, Region: "us-east-1", BizType: "dev-devtier", TenantID: "999", ProjectID: "us-east-1-f02"},
			wantRegion: "us-east-1-serverless-2",
		},
		{
			name:       "serverless f06 wins over catch-all",
			routingCtx: structs.RoutingContext{Vendor: constants.AWS, Region: "us-east-1", BizType: "dev-devtier", TenantID: "999", ProjectID: "us-east-1-f06"},
			wantRegion: "us-east-1-serverless-2",
		},
		{
			name:       "serverless f01 goes to old cluster not catch-all",
			routingCtx: structs.RoutingContext{Vendor: constants.AWS, Region: "us-east-1", BizType: "dev-devtier", TenantID: "999", ProjectID: "us-east-1-f01"},
			wantRegion: "us-east-1-serverless",
		},
		{
			name:       "nextgen wins over catch-all",
			routingCtx: structs.RoutingContext{Vendor: constants.AWS, Region: "us-east-1", BizType: "dev-tidbcloud-nextgen", TenantID: "999"},
			wantRegion: "us-east-1-nextgen",
		},
	}

	ctx := context.Background()
	for i := 0; i < 20; i++ {
		router := NewLogicalRegionRouter(mockMetaGetter)
		router.BuildPatternCache(routes)

		for _, tc := range cases {
			got, err := router.GetLogicalRegionName(ctx, tc.routingCtx)
			assert.NoError(t, err, "iteration %d case %q", i, tc.name)
			assert.Equal(t, tc.wantRegion, got, "iteration %d case %q — order should not matter", i, tc.name)
		}
	}
}
