package cvt

import (
	"google.golang.org/protobuf/proto"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globalserverlessv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/serverless/v1"
	regionalserverlessv1 "github.com/tidbcloud/tidb-management-service/api/spec/regional/serverless/v1"
	"github.com/tidbcloud/tidb-management-service/serverless-global-service/domain/entity"
)

const defaultEngineType = "MYSQL_COMPATIBLE"

func DeletedClusterEnToGlobal(en *entity.Cluster) *globalserverlessv1.ServerlessServiceCluster {
	engineType := en.EngineType
	if engineType == "" {
		engineType = defaultEngineType
	}

	regional := &regionalserverlessv1.ServerlessRegionalServiceClusterInfo{
		ClusterId: en.ClusterId,
		CreatedTs: en.CreatedAt.Unix(),
		UpdatedTs: en.UpdatedAt.Unix(),
		DeleteTs:  en.DeletedAt.Unix(),
		Region: &regionalserverlessv1.Region{
			Name:        en.Region.Id.String(),
			DisplayName: en.Region.DisplayName,
		},
		Version: en.Version,
		State:   regionalserverlessv1.ClusterState_CLUSTER_STATE_DELETED,
	}

	var creationFinishedAt *int64
	if en.CreationFinishedAt != nil {
		creationFinishedAt = proto.Int64(en.CreationFinishedAt.Unix())
	}

	return &globalserverlessv1.ServerlessServiceCluster{
		ClusterId:          en.ClusterId,
		Cluster:            regional,
		TenantId:           en.TenantId,
		CloudProvider:      en.Region.CloudProviderId.String(),
		Region:             en.Region.Id.String(),
		HasSetPwd:          en.HasSetPwd,
		UserStatus:         globalserverlessv1.UserClusterStatus_USER_CLUSTER_STATUS_DELETED,
		CreationFinishedAt: creationFinishedAt,
		RuVersion:          en.RuVersion,
		EngineType:         engineType,
	}
}

func ClusterEnToGlobal(en *entity.Cluster) *globalserverlessv1.ServerlessServiceCluster {
	global := &en.ServerlessServiceCluster

	if global.Cluster == nil {
		global.Cluster = &regionalserverlessv1.ServerlessRegionalServiceClusterInfo{
			ClusterId: en.ClusterId,
			CreatedTs: en.CreatedAt.Unix(),
			TenantId:  en.TenantId,
			ProjectId: en.ProjectId,
			Version:   en.Version,
		}
	}

	if global.UserStatus == globalserverlessv1.UserClusterStatus_USER_CLUSTER_STATUS_UNSPECIFIED {
		global.UserStatus = ClusterStatusRegionalToGlobal(global.GetCluster().GetState())
	}

	if !en.DeletedAt.IsZero() {
		global.UserStatus = globalserverlessv1.UserClusterStatus_USER_CLUSTER_STATUS_DELETED
		global.Cluster.DeleteTs = en.DeletedAt.Unix()
	}

	if en.CloudProvider != nil {
		global.CloudProvider = en.CloudProvider.Id.String()
	}

	if global.Cluster.Region == nil {
		global.Cluster.Region = &regionalserverlessv1.Region{}
	}
	if en.Region != nil {
		global.Region = en.Region.Id.String()
		global.Cluster.Region.Name = en.Region.Id.String()
		global.Cluster.Region.DisplayName = en.Region.DisplayName
		global.Cluster.Region.CloudProvider = Name2CloudProviderEnum(en.Region.CloudProviderId.String())
	}

	if en.EngineType == "" {
		global.EngineType = defaultEngineType
	} else {
		global.EngineType = en.EngineType
	}

	return global
}

func ClusterRegionalToGlobal(
	cluster *regionalserverlessv1.ServerlessRegionalServiceClusterInfo,
) *globalserverlessv1.ServerlessServiceCluster {
	global := &globalserverlessv1.ServerlessServiceCluster{
		ClusterId:        cluster.GetClusterId(),
		Cluster:          cluster,
		TenantId:         cluster.GetTenantId(),
		ProjectId:        cluster.GetProjectId(),
		CloudProvider:    CloudProviderRegionalToGlobal(cluster.GetRegion().GetCloudProvider()).String(),
		Region:           cluster.GetRegion().GetName(),
		UserStatus:       ClusterStatusRegionalToGlobal(cluster.GetState()),
		InternalEndpoint: cluster.GetProxyEndpoint(),
	}

	global.Features = append(
		global.Features,
		globalcommonv1.AvailableFeature_DISABLE_PUBLIC_LB,
		globalcommonv1.AvailableFeature_DELEGATE_USER,
	)
	return global
}

func ClusterStatusRegionalToGlobal(status regionalserverlessv1.ClusterState) globalserverlessv1.UserClusterStatus {
	switch status {
	case regionalserverlessv1.ClusterState_CLUSTER_STATE_READY:
		return globalserverlessv1.UserClusterStatus_USER_CLUSTER_STATUS_NORMAL
	case regionalserverlessv1.ClusterState_CLUSTER_STATE_CREATING:
		return globalserverlessv1.UserClusterStatus_USER_CLUSTER_STATUS_CREATING
	case regionalserverlessv1.ClusterState_CLUSTER_STATE_DELETING,
		regionalserverlessv1.ClusterState_CLUSTER_STATE_DELETED:
		return globalserverlessv1.UserClusterStatus_USER_CLUSTER_STATUS_DELETED
	default:
		return globalserverlessv1.UserClusterStatus_USER_CLUSTER_STATUS_UNSPECIFIED
	}
}

func CloudProviderRegionalToGlobal(provider regionalserverlessv1.CloudProvider) globalcommonv1.CloudProvider_Name {
	switch provider {
	case regionalserverlessv1.CloudProvider_CLOUD_PROVIDER_AWS:
		return globalcommonv1.CloudProvider_AWS
	case regionalserverlessv1.CloudProvider_CLOUD_PROVIDER_GCP:
		return globalcommonv1.CloudProvider_GCP
	case regionalserverlessv1.CloudProvider_CLOUD_PROVIDER_AZURE:
		return globalcommonv1.CloudProvider_AZURE
	case regionalserverlessv1.CloudProvider_CLOUD_PROVIDER_ALICLOUD:
		return globalcommonv1.CloudProvider_ALICLOUD
	default:
		return globalcommonv1.CloudProvider_NAME_UNSPECIFIED
	}
}
