package rbac

import (
	"regexp"

	lru "github.com/hashicorp/golang-lru/v2"
)

const resourceCacheSize = 1024

var (
	resourceCache *lru.Cache[string, string]

	ignoreRBACPaths = []string{
		"/healthz",
		"/version",
		"/ping",
	}
)

func init() {
	var err error
	resourceCache, err = lru.New[string, string](resourceCacheSize)
	if err != nil {
		panic("failed to create resource cache for rbac: " + err.Error())
	}
}

var (
	// Do not forget to update [resource url](https://github.com/tidbcloud/account/blob/main/tools/rbac-management/ALL_PRIVILEGE.json#L1517)
	//	and [role map](https://github.com/tidbcloud/account/blob/main/tools/rbac-management/ALL_ROLEBINDING.json#L1505)
	//	on account side when you add new path pattern here.
	// The resource url **must be equal** between both side.
	// See [Dedicated Mgmt Service RBAC SOP](https://pingcap.feishu.cn/wiki/P4G1wuFmuiNlMvk6P3Uc0tnZnmb) for more information.

	PathPattern2ResourceMap = map[*regexp.Regexp]string{
		// console cluster
		regexp.MustCompile(`get:/clusterManagement/clusters$`):                                "/clusterManagement/orgs/{org_id}/projects/{project_id}/clusters/list",
		regexp.MustCompile(`get:/clusterManagement/clusters/(\d+)$`):                          "/clusterManagement/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/get",
		regexp.MustCompile(`post:/clusterManagement/clusters/(\d+):dedicatedAdvancedModify$`): "/clusterManagement/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/dedicatedAdvancedModify",
		regexp.MustCompile(`post:/clusterManagement/clusters:estimatePrice$`):                 "/clusterManagement/orgs/{org_id}/projects/{project_id}/clusters/list",
		regexp.MustCompile(`post:/clusterManagement/clusters/(\d+):checkModificationRisks$`):  "/clusterManagement/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/get",
		regexp.MustCompile(`get:/clusterManagement/tidbs$`):                                   "/clusterManagement/orgs/{org_id}/tidbs/list",
		// FIXME: use data permission filter instead of api permission for now
		// API permissions can only be used after the account service synchronizes the dedicated cluster data.
		// regexp.MustCompile(`get:/clusterManagement/tidbs/(\d+)$`):                             "/clusterManagement/orgs/{org_id}/tidbs/{tidb_id}/get",
		regexp.MustCompile(`get:/clusterManagement/tidbs/(\d+)$`):             "/clusterManagement/orgs/{org_id}/tidbs/list",
		regexp.MustCompile(`post:/clusterManagement/tidbs/(\d+):bindTags$`):   "/clusterManagement/orgs/{org_id}/tidbs/{tidb_id}/tags/bind",
		regexp.MustCompile(`post:/clusterManagement/tidbs/(\d+):unbindTags$`): "/clusterManagement/orgs/{org_id}/tidbs/{tidb_id}/tags/unbind",

		// cluster migration (Org Owner only)
		regexp.MustCompile(`post:/clusterManagement/tidbs/(\d+):move$`): "/clusterManagement/orgs/{org_id}/tidbs/{tidb_id}/move",
		regexp.MustCompile(`post:/clusterManagement/tidbs:batchMove$`):  "/clusterManagement/orgs/{org_id}/tidbs/batchMove",
		regexp.MustCompile(`get:/clusterManagement/tidbs:inventory$`):   "/clusterManagement/orgs/{org_id}/tidbs/inventory",

		// project migration task (Org Owner only)
		regexp.MustCompile(`get:/clusterManagement/project-migration$`):          "/clusterManagement/orgs/{org_id}/project-migration/get",
		regexp.MustCompile(`post:/clusterManagement/project-migration:approve$`): "/clusterManagement/orgs/{org_id}/project-migration/approve",

		regexp.MustCompile(`get:/clusterManagement/regions$`):                    "/clusterManagement/orgs/{org_id}/regions/list",
		regexp.MustCompile(`get:/clusterManagement/regions:listCloudProviders$`): "/clusterManagement/orgs/{org_id}/providers/list",

		// dedicated cluster
		regexp.MustCompile("get:/dedicated/clusters$"):                                           "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/list",
		regexp.MustCompile("post:/dedicated/clusters$"):                                          "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/create",
		regexp.MustCompile(`patch:/dedicated/clusters/(\d+)$`):                                   "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/update",
		regexp.MustCompile(`delete:/dedicated/clusters/(\d+)$`):                                  "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/delete",
		regexp.MustCompile(`get:/dedicated/clusters/(\d+)$`):                                     "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/get",
		regexp.MustCompile(`post:/dedicated/clusters/(\d+):pauseCluster$`):                       "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/pause",
		regexp.MustCompile(`post:/dedicated/clusters/(\d+):resumeCluster$`):                      "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/resume",
		regexp.MustCompile(`post:/dedicated/clusters/(\d+):resetRootPassword$`):                  "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/password/update",
		regexp.MustCompile(`get:/dedicated/clusters/(\d+)/nodeInstances$`):                       "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/nodes/list",
		regexp.MustCompile(`get:/dedicated/clusters/(\d+)/nodeInstances/(\w+)-([a-zA-Z0-9-]+)$`): "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/nodes/get",
		regexp.MustCompile(`get:/dedicated/clusters:showNodeQuota$`):                             "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/nodes/quota/get",
		regexp.MustCompile(`get:/dedicated/clusters/(\d+)/logRedactionPolicy`):                   "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/logRedactionPolicy/get",
		regexp.MustCompile(`patch:/dedicated/clusters/(\d+)/logRedactionPolicy`):                 "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/logRedactionPolicy/update",

		// dedicated region
		regexp.MustCompile(`get:/dedicated/regions$`):                                                                                "/dedicated/orgs/{org_id}/projects/{project_id}/regions/list",
		regexp.MustCompile(`get:/dedicated/regions/([a-z]+)-([a-z0-9-]+)$`):                                                          "/dedicated/orgs/{org_id}/projects/{project_id}/regions/get",
		regexp.MustCompile(`get:/dedicated/regions:showCloudProviders$`):                                                             "/dedicated/orgs/{org_id}/projects/{project_id}/regions/providers/list",
		regexp.MustCompile(`get:/dedicated/regions/([a-z]+)-([a-z0-9-]+)/nodeSpecs$`):                                                "/dedicated/orgs/{org_id}/projects/{project_id}/regions/nodeSpecs/list",
		regexp.MustCompile(`get:/dedicated/regions/([a-z]+)-([a-z0-9-]+)/componentTypes/([a-zA-Z0-9-]+)/nodeSpecs/([a-zA-Z0-9-]+)$`): "/dedicated/orgs/{org_id}/projects/{project_id}/regions/nodeSpecs/get",

		// dedicated tidb group
		regexp.MustCompile(`post:/dedicated/clusters/(\d+)/tidbNodeGroups$`):                                        "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tidbNodeGroups/create",
		regexp.MustCompile(`get:/dedicated/clusters/(\d+)/tidbNodeGroups$`):                                         "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tidbNodeGroups/list",
		regexp.MustCompile(`get:/dedicated/clusters/(\d+)/tidbNodeGroups/(\d+)$`):                                   "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tidbNodeGroups/get",
		regexp.MustCompile(`patch:/dedicated/clusters/(\d+)/tidbNodeGroups/(\d+)$`):                                 "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tidbNodeGroups/update",
		regexp.MustCompile(`delete:/dedicated/clusters/(\d+)/tidbNodeGroups/(\d+)$`):                                "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tidbNodeGroups/delete",
		regexp.MustCompile(`get:/dedicated/clusters/(\d+)/tidbNodeGroups/(\d+)/publicEndpointSetting$`):             "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tidbNodeGroups/publicEndpointSetting/get",
		regexp.MustCompile(`patch:/dedicated/clusters/(\d+)/tidbNodeGroups/(\d+)/publicEndpointSetting$`):           "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tidbNodeGroups/publicEndpointSetting/update",
		regexp.MustCompile(`get:/dedicated/clusters/(\d+)/tidbNodeGroups/(\d+)/privateLinkIpAddressTypeSetting$`):   "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tidbNodeGroups/get",
		regexp.MustCompile(`patch:/dedicated/clusters/(\d+)/tidbNodeGroups/(\d+)/privateLinkIpAddressTypeSetting$`): "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tidbNodeGroups/update",

		// dedicated private endpoint
		regexp.MustCompile(`get:/dedicated/clusters/(\d+)/tidbNodeGroups/(\d+)/privateLinkService$`):                  "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tidbNodeGroups/privateLinkService/get",
		regexp.MustCompile(`get:/dedicated/clusters/(-|\d+)/tidbNodeGroups/(-|\d+)/privateEndpointConnections$`):      "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tidbNodeGroups/privateEndpointConnections/list",
		regexp.MustCompile(`post:/dedicated/clusters/(\d+)/tidbNodeGroups/(\d+)/privateEndpointConnections$`):         "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tidbNodeGroups/privateEndpointConnections/create",
		regexp.MustCompile(`get:/dedicated/clusters/(\d+)/tidbNodeGroups/(\d+)/privateEndpointConnections/(\d+)$`):    "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tidbNodeGroups/privateEndpointConnections/get",
		regexp.MustCompile(`delete:/dedicated/clusters/(\d+)/tidbNodeGroups/(\d+)/privateEndpointConnections/(\d+)$`): "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tidbNodeGroups/privateEndpointConnections/delete",

		// dedicated network
		regexp.MustCompile(`get:/dedicated/networkContainers$`):              "/dedicated/orgs/{org_id}/projects/{project_id}/networkContainers/list",
		regexp.MustCompile(`post:/dedicated/networkContainers$`):             "/dedicated/orgs/{org_id}/projects/{project_id}/networkContainers/create",
		regexp.MustCompile(`get:/dedicated/networkContainers/(\d+)$`):        "/dedicated/orgs/{org_id}/projects/{project_id}/networkContainers/get",
		regexp.MustCompile(`delete:/dedicated/networkContainers/(\d+)$`):     "/dedicated/orgs/{org_id}/projects/{project_id}/networkContainers/delete",
		regexp.MustCompile(`get:/dedicated/vpcPeerings$`):                    "/dedicated/orgs/{org_id}/projects/{project_id}/vpcPeerings/list",
		regexp.MustCompile(`post:/dedicated/vpcPeerings$`):                   "/dedicated/orgs/{org_id}/projects/{project_id}/vpcPeerings/create",
		regexp.MustCompile(`get:/dedicated/vpcPeerings/([a-zA-Z0-9-]+)$`):    "/dedicated/orgs/{org_id}/projects/{project_id}/vpcPeerings/get",
		regexp.MustCompile(`delete:/dedicated/vpcPeerings/([a-zA-Z0-9-]+)$`): "/dedicated/orgs/{org_id}/projects/{project_id}/vpcPeerings/delete",

		// dedicated maintenance
		regexp.MustCompile(`get:/dedicated/maintenanceWindows$`):                   "/dedicated/orgs/{org_id}/projects/{project_id}/maintenanceWindows/list",
		regexp.MustCompile(`get:/dedicated/maintenanceWindows/([a-zA-Z0-9-]+)$`):   "/dedicated/orgs/{org_id}/projects/{project_id}/maintenanceWindows/get",
		regexp.MustCompile(`patch:/dedicated/maintenanceWindows/([a-zA-Z0-9-]+)$`): "/dedicated/orgs/{org_id}/projects/{project_id}/maintenanceWindows/update",
		regexp.MustCompile(`get:/dedicated/maintenanceTasks`):                      "/dedicated/orgs/{org_id}/projects/{project_id}/maintenanceTasks/list",
		regexp.MustCompile(`get:/dedicated/maintenanceTasks/(\d+)$`):               "/dedicated/orgs/{org_id}/projects/{project_id}/maintenanceTasks/get",
		regexp.MustCompile(`patch:/dedicated/maintenanceTasks/(\d+)$`):             "/dedicated/orgs/{org_id}/projects/{project_id}/maintenanceTasks/defer",

		// dedicated database audit log
		// config
		regexp.MustCompile(`get:/dedicated/clusters/(\d+)/auditLogConfig$`):                                      "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/auditLogConfig/get",
		regexp.MustCompile(`patch:/dedicated/clusters/(\d+)/auditLogConfig$`):                                    "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/auditLogConfig/update",
		regexp.MustCompile(`get:/dedicated/clusters/(\d+)/auditLogConfig:showObjectStorageAccessIamPrincipal$`):  "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/auditLogConfig/iam/get",
		regexp.MustCompile(`get:/dedicated/clusters/(\d+)/auditLogConfig:queryAuditLogFiles$`):                   "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/auditLogConfig/get",
		regexp.MustCompile(`post:/dedicated/clusters/(\d+)/auditLogConfig:generateAuditLogFileDownloadAddress$`): "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/auditLogConfig/generateAuditLogFileDownloadAddress/get",
		// Filter rule.
		// Rule id can be a 1-128 character string or a number.
		regexp.MustCompile(`post:/dedicated/clusters/(\d+)/auditLogFilterRules$`):                                      "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/auditLogFilterRules/create",
		regexp.MustCompile(`get:/dedicated/clusters/(\d+)/auditLogFilterRules$`):                                       "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/auditLogFilterRules/list",
		regexp.MustCompile(`get:/dedicated/clusters/(\d+)/auditLogFilterRules/(.{1,128})$`):                            "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/auditLogFilterRules/get",
		regexp.MustCompile(`delete:/dedicated/clusters/(\d+)/auditLogFilterRules/(.{1,128})$`):                         "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/auditLogFilterRules/delete",
		regexp.MustCompile(`post:/dedicated/clusters/(\d+)/auditLogFilterRules/(.{1,128}):replaceAuditLogFilterRule$`): "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/auditLogFilterRules/create",

		// dedicated cmek
		regexp.MustCompile(`post:/dedicated/cmeks$`):                           "/dedicated/orgs/{org_id}/projects/{project_id}/cmeks/create",
		regexp.MustCompile(`get:/dedicated/cmeks/(\d+)$`):                      "/dedicated/orgs/{org_id}/projects/{project_id}/cmeks/get",
		regexp.MustCompile(`get:/dedicated/cmeks$`):                            "/dedicated/orgs/{org_id}/projects/{project_id}/cmeks/list",
		regexp.MustCompile(`delete:/dedicated/cmeks/(\d+)$`):                   "/dedicated/orgs/{org_id}/projects/{project_id}/cmeks/delete",
		regexp.MustCompile(`get:/dedicated/cmeks:showCmekAccessIamPrincipal$`): "/dedicated/orgs/{org_id}/projects/{project_id}/cmeks/showCmekAccessIamPrincipal",

		// dedicated tags
		regexp.MustCompile(`post:/dedicated/clusters/(\d+):bindTags$`):   "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tags/bind",
		regexp.MustCompile(`post:/dedicated/clusters/(\d+):unbindTags$`): "/dedicated/orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tags/unbind",

		// serverless cluster
		regexp.MustCompile("get:/serverless/clusters$"):                           "/serverless/orgs/{org_id}/projects/{project_id}/clusters/list",
		regexp.MustCompile("post:/serverless/clusters$"):                          "/serverless/orgs/{org_id}/projects/{project_id}/clusters/create",
		regexp.MustCompile("post:/serverless/clusters:claimFromZero$"):            "/serverless/orgs/{org_id}/projects/{project_id}/clusters/claimFromZero",
		regexp.MustCompile("post:/serverless/clusters:takeoverFromPool$"):         "/serverless/orgs/{org_id}/projects/{project_id}/clusters/takeoverFromPool",
		regexp.MustCompile(`patch:/serverless/clusters/(\d+)$`):                   "/serverless/orgs/{org_id}/projects/{project_id}/tidbs/{cluster_id}/update",
		regexp.MustCompile(`delete:/serverless/clusters/(\d+)$`):                  "/serverless/orgs/{org_id}/projects/{project_id}/tidbs/{cluster_id}/delete",
		regexp.MustCompile(`get:/serverless/clusters/(\d+)$`):                     "/serverless/orgs/{org_id}/projects/{project_id}/tidbs/{cluster_id}/get",
		regexp.MustCompile(`put:/serverless/clusters/(\d+)/password$`):            "/serverless/orgs/{org_id}/projects/{project_id}/tidbs/{cluster_id}/password/update",
		regexp.MustCompile(`post:/serverless/clusters/(\d+):rotateRootPassword$`): "/serverless/orgs/{org_id}/projects/{project_id}/tidbs/{cluster_id}/password/update",
		regexp.MustCompile(`post:/serverless/clusters/(\d+):redeemRootPassword$`): "/serverless/orgs/{org_id}/projects/{project_id}/tidbs/{cluster_id}/password/update",
		regexp.MustCompile("get:/serverless/regions$"):                            "/serverless/orgs/{org_id}/regions/list",
		regexp.MustCompile("get:/serverless/regions:listCloudProviders$"):         "/serverless/orgs/{org_id}/regions/list",
		regexp.MustCompile("post:/serverless/clusters:batchCreate$"):              "/serverless/orgs/{org_id}/projects/{project_id}/clusters/batchCreate",
		regexp.MustCompile("get:/serverless/clusters:batchGet$"):                  "/serverless/orgs/{org_id}/projects/{project_id}/clusters/batchGet",
		regexp.MustCompile("post:/serverless/clusters:batchDelete$"):              "/serverless/orgs/{org_id}/clusters/batchDelete",

		// serverless tags
		regexp.MustCompile(`post:/serverless/clusters/(\d+):bindTags$`):   "/serverless/orgs/{org_id}/projects/{project_id}/tidbs/{cluster_id}/tags/bind",
		regexp.MustCompile(`post:/serverless/clusters/(\d+):unbindTags$`): "/serverless/orgs/{org_id}/projects/{project_id}/tidbs/{cluster_id}/tags/unbind",

		// serverless shadow pools
		regexp.MustCompile(`get:/serverless/shadowPools$`):                              "/serverless/orgs/{org_id}/projects/{project_id}/shadowPools/list",
		regexp.MustCompile(`post:/serverless/shadowPools$`):                             "/serverless/orgs/{org_id}/projects/{project_id}/shadowPools/create",
		regexp.MustCompile(`get:/serverless/shadowPools/(\d+)$`):                        "/serverless/orgs/{org_id}/projects/{project_id}/shadowPools/{shadow_pool_id}/get",
		regexp.MustCompile(`delete:/serverless/shadowPools/(\d+)$`):                     "/serverless/orgs/{org_id}/projects/{project_id}/shadowPools/{shadow_pool_id}/delete",
		regexp.MustCompile(`patch:/serverless/shadowPools/(\d+)$`):                      "/serverless/orgs/{org_id}/projects/{project_id}/shadowPools/{shadow_pool_id}/update",
		regexp.MustCompile(`post:/serverless/shadowPools/(\d+):replaceInitSqls$`):       "/serverless/orgs/{org_id}/projects/{project_id}/shadowPools/{shadow_pool_id}/replaceInitSqls",
		regexp.MustCompile(`post:/serverless/shadowPools/(\d+):replaceInstanceDemand$`): "/serverless/orgs/{org_id}/projects/{project_id}/shadowPools/{shadow_pool_id}/replaceInstanceDemand",

		// nextgen  regions
		regexp.MustCompile(`get:/regions$`):                                   "/nextgen/orgs/{org_id}/regions/list",
		regexp.MustCompile(`get:/regions:listCloudProviders$`):                "/nextgen/orgs/{org_id}/regions/providers/list",
		regexp.MustCompile(`get:/opsAuditLogSettings$`):                       "/nextgen/orgs/{org_id}/opsAuditLogSettings/list",
		regexp.MustCompile(`get:/regions:listCapacities$`):                    "/nextgen/orgs/{org_id}/regions/capacities/list",
		regexp.MustCompile(`get:/regions/([^/]+)/nodeSpecs$`):                 "/nextgen/orgs/{org_id}/regions/nodeSpecs/list",
		regexp.MustCompile(`get:/regions/([^/]+):planResourcePoolCidr$`):      "/nextgen/orgs/{org_id}/regions/resourcePoolCidr/plan",
		regexp.MustCompile(`post:/regions/([^/]+):validateResourcePoolCidr$`): "/nextgen/orgs/{org_id}/regions/resourcePoolCidr/validate",

		// nextgen resource pools
		regexp.MustCompile(`post:/resourcePools$`):                               "/nextgen/orgs/{org_id}/resourcePools/create",
		regexp.MustCompile(`get:/resourcePools$`):                                "/nextgen/orgs/{org_id}/resourcePools/list",
		regexp.MustCompile(`get:/resourcePools/(\d+)$`):                          "/nextgen/orgs/{org_id}/resourcePools/{resource_pool_id}/get",
		regexp.MustCompile(`patch:/resourcePools/(\d+)$`):                        "/nextgen/orgs/{org_id}/resourcePools/{resource_pool_id}/update",
		regexp.MustCompile(`delete:/resourcePools/(\d+)$`):                       "/nextgen/orgs/{org_id}/resourcePools/{resource_pool_id}/delete",
		regexp.MustCompile(`post:/resourcePools/(\d+):resumeResourcePool$`):      "/nextgen/orgs/{org_id}/resourcePools/{resource_pool_id}/resume",
		regexp.MustCompile(`get:/resourcePools/(\d+)/capacityConstraints$`):      "/nextgen/orgs/{org_id}/resourcePools/{resource_pool_id}/capacityConstraints/get",
		regexp.MustCompile(`post:/resourcePools/(\d+):resizeCapacity$`):          "/nextgen/orgs/{org_id}/resourcePools/{resource_pool_id}/capacity/resize",
		regexp.MustCompile(`post:/resourcePools/(\d+):upsertCloudResourceTags$`): "/nextgen/orgs/{org_id}/resourcePools/{resource_pool_id}/cloudResourceTags/upsert",

		regexp.MustCompile(`get:/byocVcpuPools$`):                                       "/nextgen/orgs/{org_id}/byocVcpuPools/list",
		regexp.MustCompile(`patch:/byocVcpuPools/(\d+)$`):                               "/nextgen/orgs/{org_id}/byocVcpuPools/update",
		regexp.MustCompile(`get:/byocVcpuPools/(\d+)/sharedComponentScaleConstraints$`): "/nextgen/orgs/{org_id}/byocVcpuPools/sharedComponentScaleConstraints/get",
		regexp.MustCompile(`post:/byocVcpuPools/(\d+):scaleByocSharedComponents$`):      "/nextgen/orgs/{org_id}/byocVcpuPools/sharedComponents/scale",

		// nextgen tidb
		regexp.MustCompile(`get:/tidbs$`):                          "/nextgen/orgs/{org_id}/tidbs/list",
		regexp.MustCompile(`post:/tidbs$`):                         "/nextgen/orgs/{org_id}/tidbs/create",
		regexp.MustCompile(`get:/tidbs/(\d+)$`):                    "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/get",
		regexp.MustCompile(`patch:/tidbs/(\d+)$`):                  "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/update",
		regexp.MustCompile(`delete:/tidbs/(\d+)$`):                 "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/delete",
		regexp.MustCompile(`post:/tidbs/(\d+):resumeTidb$`):        "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/resume",
		regexp.MustCompile(`post:/tidbs/(\d+):resetRootPassword$`): "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/password/update",
		regexp.MustCompile(`get:/tidbs/(\d+)/cloudProviderInfo$`):  "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/cloudProviderInfo/get",
		regexp.MustCompile(`post:/tidbs:estimatePrice$`):           "/nextgen/orgs/{org_id}/tidbs/estimatePrice/calculate",
		regexp.MustCompile(`post:/tidbs:calculateMinRcu$`):         "/nextgen/orgs/{org_id}/tidbs/calculateMinRcu",
		regexp.MustCompile(`get:/capacityOptions$`):                "/nextgen/orgs/{org_id}/tidbs/capacityOptions/list",
		regexp.MustCompile(`get:/tidbs/(\d+)/caCertificateUrl$`):   "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/caCertificateUrl/get",

		// nextgen tags
		regexp.MustCompile(`post:/tidbs/(\d+):bindTags$`):   "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/tags/bind",
		regexp.MustCompile(`post:/tidbs/(\d+):unbindTags$`): "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/tags/unbind",

		// next tidb public endpoint
		regexp.MustCompile(`get:/tidbs/(\d+)/publicConnectionSetting$`):   "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/publicConnectionSetting/get",
		regexp.MustCompile(`patch:/tidbs/(\d+)/publicConnectionSetting$`): "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/publicConnectionSetting/update",

		// next tidb BYOC peering
		regexp.MustCompile(`get:/byoc/tidbs/(\d+)/vpcPeerings$`):                  "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/vpcPeerings/list",
		regexp.MustCompile(`get:/byoc/tidbs/(\d+)/vpcPeerings/([a-zA-Z0-9-]+)$`):  "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/vpcPeerings/get",
		regexp.MustCompile(`get:/byoc/tidbs/(\d+)/vpcPeeringAllowlistSetting$`):   "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/vpcPeeringAllowlistSetting/get",
		regexp.MustCompile(`patch:/byoc/tidbs/(\d+)/vpcPeeringAllowlistSetting$`): "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/vpcPeeringAllowlistSetting/update",
		regexp.MustCompile(`get:/tidbs/(\d+)/planReplayer/status$`):               "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/planReplayer/status/get",
		regexp.MustCompile(`patch:/tidbs/(\d+)/planReplayer/status$`):             "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/planReplayer/status/update",

		// next tidb private link service
		regexp.MustCompile(`get:/tidbs/(\d+)/privateLinkService$`):                  "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/privateLinkService/get",
		regexp.MustCompile(`get:/tidbs/(\d+)/privateEndpointConnections$`):          "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/privateEndpointConnections/list",
		regexp.MustCompile(`post:/tidbs/(\d+)/privateEndpointConnections$`):         "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/privateEndpointConnections/create",
		regexp.MustCompile(`get:/tidbs/(\d+)/privateEndpointConnections/(\d+)$`):    "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/privateEndpointConnections/get",
		regexp.MustCompile(`delete:/tidbs/(\d+)/privateEndpointConnections/(\d+)$`): "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/privateEndpointConnections/delete",

		// nextgen br
		regexp.MustCompile(`post:/tidbs/(\d+)/backups$`):         "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/backups/create",
		regexp.MustCompile(`get:/tidbs/(\d+)/backups$`):          "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/backups/list",
		regexp.MustCompile(`delete:/tidbs/(\d+)/backups/(\d+)$`): "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/backups/delete",
		regexp.MustCompile(`post:/tidbs:restore`):                "/nextgen/orgs/{org_id}/tidbs/restore",
		regexp.MustCompile(`post:/tidbs:validateClassicBackup`):  "/nextgen/orgs/{org_id}/tidbs/restore",
		regexp.MustCompile(`get:/tidbs/(\d+):restoreStatus$`):    "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/restoreStatus/get",
		regexp.MustCompile(`get:/tidbs/(\d+):getRestoreStatus$`): "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/restoreStatus/get",
		regexp.MustCompile(`get:/tidbs/(\d+)/backupPolicies$`):   "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/backupSetting/get",
		regexp.MustCompile(`get:/tidbs/(\d+)/backupSetting$`):    "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/backupSetting/get",
		regexp.MustCompile(`patch:/tidbs/(\d+)/backupSetting$`):  "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/backupSetting/update",
		regexp.MustCompile(`get:/backups$`):                      "/nextgen/orgs/{org_id}/backups/list",
		regexp.MustCompile(`get:/backups/(\d+)$`):                "/nextgen/orgs/{org_id}/backups/get",
		regexp.MustCompile(`delete:/backups/(\d+)$`):             "/nextgen/orgs/{org_id}/backups/delete",
		regexp.MustCompile(`get:/backups:listDeletedTidbs$`):     "/nextgen/orgs/{org_id}/backups/deletedTidbs/list",

		// nextgen audit log
		regexp.MustCompile(`get:/tidbs/(\d+)/auditLogSetting$`):              "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/auditLogSetting/get",
		regexp.MustCompile(`patch:/tidbs/(\d+)/auditLogSetting$`):            "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/auditLogSetting/update",
		regexp.MustCompile(`get:/tidbs/(\d+)/auditLogFilterRules$`):          "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/auditLogFilterRules/list",
		regexp.MustCompile(`post:/tidbs/(\d+)/auditLogFilterRules$`):         "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/auditLogFilterRules/create",
		regexp.MustCompile(`get:/tidbs/(\d+)/auditLogFilterRules/(\d+)$`):    "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/auditLogFilterRules/get",
		regexp.MustCompile(`delete:/tidbs/(\d+)/auditLogFilterRules/(\d+)$`): "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/auditLogFilterRules/delete",
		regexp.MustCompile(`patch:/tidbs/(\d+)/auditLogFilterRules/(\d+)$`):  "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/auditLogFilterRules/update",

		// nextgen log redaction policy
		regexp.MustCompile(`get:/tidbs/(\d+)/logRedactionPolicy$`):   "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/logRedactionPolicy/get",
		regexp.MustCompile(`patch:/tidbs/(\d+)/logRedactionPolicy$`): "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/logRedactionPolicy/update",

		// nextgen quota
		regexp.MustCompile(`get:/quotas$`): "/nextgen/orgs/{org_id}/quotas/list",

		// nextgen cmek
		regexp.MustCompile(`get:/cmeks:principal$`):                       "/nextgen/orgs/{org_id}/cmeks/principal",
		regexp.MustCompile(`post:/cmeks:verifyPrincipal$`):                "/nextgen/orgs/{org_id}/cmeks/verifyPrincipal",
		regexp.MustCompile(`get:/cmeks/(\d+)$`):                           "/nextgen/orgs/{org_id}/cmeks/get",
		regexp.MustCompile(`get:/cmeks$`):                                 "/nextgen/orgs/{org_id}/cmeks/get",
		regexp.MustCompile(`patch:/tidbs/(\d+)/dualLayerDataEncryption$`): "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/update",
		regexp.MustCompile(`get:/tidbs/(\d+)/dualLayerDataEncryption$`):   "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/get",

		// nextgen export
		regexp.MustCompile(`get:/tidbs/(\d+)/exports$`):               "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/exports/list",
		regexp.MustCompile(`get:/tidbs/(\d+)/exports/(\d+)$`):         "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/exports/get",
		regexp.MustCompile(`post:/tidbs/(\d+)/exports$`):              "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/exports/create",
		regexp.MustCompile(`delete:/tidbs/(\d+)/exports/(\d+)$`):      "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/exports/delete",
		regexp.MustCompile(`post:/tidbs/(\d+)/exports/(\d+):cancel$`): "/nextgen/orgs/{org_id}/tidbs/{tidb_id}/exports/cancel",

		// fs region
		// public OpenAPI (fs.tidbapi.com/v1beta2/regions) arrives as /fs/v1beta2/regions and
		// is normalized to /fs/regions; the console UI path (/api/v2025/fs/v1beta2/regions)
		// is normalized to /fs/v1beta2/regions.
		regexp.MustCompile(`get:/fs/regions$`):                 "/fs/orgs/{org_id}/regions/list",
		regexp.MustCompile(`get:/fs/regions/([^/]+)$`):         "/fs/orgs/{org_id}/regions/get",
		regexp.MustCompile(`get:/fs/v1beta2/regions$`):         "/fs/orgs/{org_id}/regions/list",
		regexp.MustCompile(`get:/fs/v1beta2/regions/([^/]+)$`): "/fs/orgs/{org_id}/regions/get",
	}
)
