/******************************************************************************
 * Copyright (c)  2022 PingCAP, Inc.                                          *
 * Licensed under the Apache License, Version 2.0 (the "License");            *
 * you may not use this file except in compliance with the License.           *
 * You may obtain a copy of the License at                                    *
 *                                                                            *
 * http://www.apache.org/licenses/LICENSE-2.0                                 *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 ******************************************************************************/

/*******************************************************************************
 * @File: meta.go
 * @Description:
 * @Author: jiangxunyu@pingcap.com
 * @Version: 1.0.0
 * @Date: 2022/6/7 14:49
*******************************************************************************/

package structs

import (
	"fmt"

	"github.com/tidbcloud/observability/pkg/common/constants"
)

// GlobalServiceMeta
// @Description: metadata information for vendor and regional mapping relationships
type GlobalServiceMeta struct {
	MaxSpec string                                    `json:"maxSpec"`
	Vendors map[constants.ProvidedVendor][]RegionInfo `json:"vendors"`
	// Auth0 issuer url and API Audience
	Auth0           Auth0Info    `json:"auth0"`
	ServerConfig    ServerConfig `json:"server"`
	EvaluationImage string       `json:"evaluationImage"`
	// Route table for logical region routing, contains entries of <{vendor}-{physical-region}, <{route-regex}, {logical-region}>>
	Routes RouteTable `json:"routes,omitempty"`
}

// RegionInfo
// @Description: region routing information
type RegionInfo struct {
	Region  string           `json:"region"`
	Routers []RegionalRouter `json:"routers"`
}

// RegionalRouter
// @Description: region routing details
type RegionalRouter struct {
	// Address of regional control plane.
	DnsAddress string `json:"dnsAddress"`
	// Address of regional data plane.
	DataplaneAddress  string `json:"dataplaneAddress"`
	Primary           bool   `json:"primary,omitempty"`
	LogicalRegionName string `json:"logicalRegionName"`
	// principal used to access regional, e.g. aws-role-arn used to access aws api gateway
	AccessPrincipal string `json:"accessPrincipal,omitempty"`
	// external id used to access regional, e.g. external id used to access aws api gateway
	AccessExternalID string `json:"accessExternalID,omitempty"`
}

// Auth0Info
// @Description: auth0 authentication information
type Auth0Info struct {
	IssuerURL    string `json:"issuerUrl"`
	Audience     string `json:"audience"`
	ClientID     string `json:"clientId"`
	ClientSecret string `json:"clientSecret"`
}

type ServerConfig struct {
	DisableAuditLog             bool              `json:"disableAuditLog"`
	EnableAuditFilter           bool              `json:"enableAuditFilter"`
	BizToAccountProviderSvcAddr map[string]string `json:"bizToAccountProviderSvcAddr"`
	BizToOpenAPISvcAddr         map[string]string `json:"bizToOpenAPISvcAddr"`
	OpenAPIWhitelistTenants     []string          `json:"openAPIWhitelistTenants"`
	InternalUserTokenVerifyURL  string            `json:"internalUserTokenVerifyURL"`
	EnvToMgmtSvcAddr            map[string]string `json:"envToMgmtSvcAddr"`
}

// RouteTable represents the routing configuration for logical regions
// Key: route key in format "{vendor}-{physical-region}" (e.g., "aws-us-west-1")
// Value: routing patterns mapping business patterns to logical regions
type RouteTable map[string]RoutingPatterns

// RoutingPatterns maps business routing patterns to logical region names
// Key: routing pattern in format "{biz-type}:{tenant-id}:{project-id}:{application-id}" (e.g., "dev-devtier:.*:f02:.*")
// Legacy 3-segment patterns (without project-id) are auto-upgraded to 4 segments.
// Value: logical region name (e.g., "logical-region-1")
type RoutingPatterns map[string]string

func GetRouteAddress(region RegionInfo) (routeAddress string) {
	if len(region.Routers) == 1 {
		routeAddress = region.Routers[0].DnsAddress
	} else {
		// if there are multiple region routes, get the dns address of the primary tag
		for _, router := range region.Routers {
			if router.Primary {
				routeAddress = router.DnsAddress
				break
			}
		}
	}
	return
}

// RoutingContext
// @Description: context information for routing decisions
type RoutingContext struct {
	// cloud provider, e.g. aws,gcp,azure,alicloud
	Vendor constants.ProvidedVendor `json:"vendor"`
	// physical region in cloud providers
	Region   string `json:"region"`
	BizType  string `json:"bizType"`
	TenantID string `json:"tenantID"`
	// ProjectID is an o11y-level project identifier used to further partition
	// routing within the same BizType + TenantID (e.g. serverless parent clusters).
	ProjectID string `json:"projectID"`
	// ApplicationID is the cluster id (e.g. serverless parent cluster "devtier-infra").
	ApplicationID string `json:"applicationID"`
	// ShowDeleted indicates the request is targeting deleted-cluster lookup
	// semantics and should resolve routing against deleted child clusters too.
	ShowDeleted bool `json:"showDeleted,omitempty"`
	// KubernetesID, when set (via X-Kubernetes-Id header), allows the serverless
	// child→parent resolver to skip the mgmt lookup and use this value directly
	// as the kubernetes name for projectID extraction.
	KubernetesID string `json:"kubernetesID,omitempty"`
	// LogicalRegion, if set, takes precedence over (Vendor, Region, BizType,
	// TenantID) and resolves the regional router directly by logical region
	// name via LogicalRegionRouter.
	LogicalRegion string `json:"logicalRegion,omitempty"`
}

// BuildBizRouteKey builds a 4-segment routing key used for route table matching.
//
// Format: {bizType}:{tenantID}:{projectID}:{applicationID}
//
// Granularity goes from coarse to fine: biz < tenant < project < app.
// Missing projectID / applicationID fields are filled with the wildcard ".*".
// Legacy 3-segment route patterns are upgraded to 4 segments (projectID
// wildcard inserted) during BuildPatternCache, so this key is always 4 segments.
func (r *RoutingContext) BuildBizRouteKey() string {
	projectID := r.ProjectID
	if projectID == "" {
		projectID = ".*"
	}
	if r.ApplicationID != "" {
		return fmt.Sprintf("%s:%s:%s:%s", r.BizType, r.TenantID, projectID, r.ApplicationID)
	}
	return fmt.Sprintf("%s:%s:%s:.*", r.BizType, r.TenantID, projectID)
}

func (r *RoutingContext) BuildRegionRouteKey() string {
	return fmt.Sprintf("%s-%s", r.Vendor, r.Region)
}
