package service

import (
	"context"
	"fmt"
	"strings"

	"dataservices/commons/constants"
	"dataservices/commons/http"
	dto "dataservices/internal/dto/dataapi"

	"github.com/tidbcloud/core-svc/idl/pbgen/proto/core"
	errs "github.com/tidbcloud/tiinf/errs"
)

type RegionalCapability string

const (
	RegionalCapabilitySQLMainChain      RegionalCapability = "sql main-chain"
	RegionalCapabilityClusterStatus     RegionalCapability = "cluster status"
	RegionalCapabilityDataSourceBinding RegionalCapability = "data source binding"
	RegionalCapabilityEndpointTest      RegionalCapability = "endpoint test"
	RegionalCapabilityCustomDomain      RegionalCapability = "custom domain"
	RegionalCapabilityDataAppLog        RegionalCapability = "dataapp log"
	RegionalCapabilityDataAppMetrics    RegionalCapability = "dataapp metrics"
	RegionalCapabilityAutoGenerateRoute RegionalCapability = "auto generate endpoint"
)

// GuardRegionalCapabilityForCluster centralizes the V2 allowlist. AWS keeps the
// legacy behavior unchanged, while AliCloud shared/serverless only allows the SQL
// main-chain and rejects unsupported capabilities in global before they hit regional.
func GuardRegionalCapabilityForCluster(cluster *core.Cluster, capability RegionalCapability) error {
	if capability == RegionalCapabilitySQLMainChain || !usesProviderScopedRegionalHost(cluster) {
		return nil
	}
	return newUnsupportedRegionalCapabilityErr(capability)
}

// GuardRegionalCapabilityForDataApp applies the same V2 allowlist to app-scoped
// capabilities after resolving the app's linked clusters.
func GuardRegionalCapabilityForDataApp(ctx context.Context, appID uint64, capability RegionalCapability) error {
	return GuardRegionalCapabilityForDataAppRegion(ctx, appID, "", capability)
}

// GuardRegionalCapabilityForDataAppRegion is used for region-specific app calls
// such as custom domain operations where only one default domain region is targeted.
func GuardRegionalCapabilityForDataAppRegion(ctx context.Context, appID uint64, region string, capability RegionalCapability) error {
	if capability == RegionalCapabilitySQLMainChain {
		return nil
	}

	appClusters, err := ListAppCluster(ctx, dto.ListAppClusterReq{DataappID: appID})
	if err != nil {
		return err
	}
	if usesProviderScopedRegionalHostForAppClusters(appClusters, region) {
		return newUnsupportedRegionalCapabilityErr(capability)
	}
	return nil
}

func newUnsupportedRegionalCapabilityErr(capability RegionalCapability) error {
	return errs.NewBadRequest(fmt.Sprintf("%s is unsupported for alicloud serverless", capability), nil)
}

func usesProviderScopedRegionalHost(clusterInfo *core.Cluster) bool {
	if clusterInfo == nil {
		return false
	}
	return http.ProviderForRegionalHostPrefix(clusterInfo.CloudProviderName, clusterInfo.GetDeployType()) != ""
}

func usesProviderScopedRegionalHostForAppClusters(appClusters []dto.AppClusterInfo, region string) bool {
	for _, appCluster := range appClusters {
		if region != "" && appCluster.RegionCode != region {
			continue
		}
		if strings.EqualFold(appCluster.Cloud, constants.ClusterCloudProviderAliCloud) &&
			appCluster.TierType == core.DeployType_DEPLOY_TYPE_SHARED.String() {
			return true
		}
	}
	return false
}
