package cluster_svc

import (
	"github.com/shopspring/decimal"
	"github.com/tidbcloud/serverless-service/idl/pbgen/proto/rpc"
	"github.com/tidbcloud/serverless-service/internal/domain/constant"
	"github.com/tidbcloud/serverless-service/internal/domain/entity"
	"github.com/tidbcloud/serverless-service/internal/domain/repo"
	"google.golang.org/protobuf/types/known/timestamppb"
)

func dolloarDeToCentsUint(dollar decimal.Decimal) uint32 {
	return uint32(dollar.Mul(constant.DolloarToCents).IntPart())
}

func ConvertClusterRUModePb2En(mode rpc.Cluster_RUMode) constant.ClusterRUMode {
	switch mode {
	case rpc.Cluster_RUMode_STANDARD:
		return constant.ClusterRUModeStandard
	case rpc.Cluster_RUMode_THROTTLED:
		return constant.ClusterRUModeThrottled
	default:
		return constant.ClusterRUModeStandard
	}
}

func ConvertClusterRUModeEn2Pb(mode constant.ClusterRUMode) rpc.Cluster_RUMode {
	switch mode {
	case constant.ClusterRUModeStandard:
		return rpc.Cluster_RUMode_STANDARD
	case constant.ClusterRUModeThrottled:
		return rpc.Cluster_RUMode_THROTTLED
	default:
		return rpc.Cluster_RUMode_UNSPECIFIED
	}
}

func ConvertClusterFilterPb2En(filter *rpc.Cluster_Filter) *repo.ClusterFilter {
	if filter == nil {
		return nil
	}
	res := &repo.ClusterFilter{
		TenantIds:  filter.TenantIds,
		ProjectIds: filter.ProjectIds,
		ClusterIds: filter.ClusterIds,
		Regions:    filter.Regions,
		RuModes:    make([]constant.ClusterRUMode, len(filter.RuModes)),
		IsPaid:     filter.IsPaid,
	}
	for i, mode := range filter.RuModes {
		res.RuModes[i] = ConvertClusterRUModePb2En(mode)
	}
	return res
}

func ConvertClusterEn2Pb(cluster *entity.Cluster) *rpc.Cluster {
	return &rpc.Cluster{
		Id:         cluster.ID,
		TenantId:   cluster.TenantID,
		ProjectId:  cluster.ProjectID,
		KeyspaceId: cluster.KeyspaceID,
		CreateTime: timestamppb.New(cluster.CreatedTime),
		Region:     cluster.RegionName,
		SpendLimit: dolloarDeToCentsUint(cluster.SpendLimit),
		FreeCredit: dolloarDeToCentsUint(cluster.FreeCredit),
		RuMode:     ConvertClusterRUModeEn2Pb(cluster.RuMode),
	}
}

func Convert2GetResp(
	cluster *entity.Cluster, ruCost, rowStorageCost decimal.Decimal,
) *rpc.GetClusterResp {
	return &rpc.GetClusterResp{
		Id:         cluster.ID,
		CreateTime: timestamppb.New(cluster.CreatedTime),
		Region:     cluster.RegionName,
		SpendLimit: dolloarDeToCentsUint(cluster.SpendLimit),
		FreeCredit: dolloarDeToCentsUint(cluster.FreeCredit),
		RuMode:     ConvertClusterRUModeEn2Pb(cluster.RuMode),
		Spent: &rpc.Cluster_Spent{
			RequestUnit: dolloarDeToCentsUint(ruCost),
			RowStorage:  dolloarDeToCentsUint(rowStorageCost),
		},
	}
}

func ConvertSpendLimitEventStatusEn2pb(status string) rpc.SpendLimitEvent_Status {
	switch status {
	case constant.SpendLimitEventStatusHandy,
		constant.SpendLimitEventStatusCreateCluster,
		constant.SpendLimitEventStatusModifySpendLimit:
		return rpc.SpendLimitEvent_STATUS_SETTING
	case constant.SpendLimitEventStatusFit:
		return rpc.SpendLimitEvent_STATUS_FIT
	case constant.SpendLimitEventStatusExcessive:
		return rpc.SpendLimitEvent_STATUS_EXCESSIVE
	default:
		return rpc.SpendLimitEvent_STATUS_UNSPECIFIED
	}
}

func ConvertSpendLimitEventEn2Pb(record *entity.ClusterTidbPool) *rpc.SpendLimitEvent {
	return &rpc.SpendLimitEvent{
		CreateTime: timestamppb.New(record.CreatedAt),
		Status:     ConvertSpendLimitEventStatusEn2pb(record.SpendLimitStatus),
	}
}
