package common

import (
	"context"
	"strconv"

	"github.com/samber/lo"

	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	openapidedicatedv1beta1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/dedicated/v1beta1"
	regionapp "github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/app/openapi/dedicated/region"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/pkg/common"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func GetPriceNodeSpecs(
	ctx context.Context,
	regionSvc regionapp.Server,
	openapiRegionId, requestTikvSpecKey, requestTiflashSpecKey, projectId string,
) (desiredTikvSpec, desiredTiflashSpec *openapidedicatedv1beta1.NodeSpec, _ bizerr.BizError) {
	desiredTikvSpec, err := regionSvc.GetNodeSpecForPrice(ctx, &openapidedicatedv1beta1.GetNodeSpecRequest{
		RegionId:      openapiRegionId,
		ComponentType: openapidedicatedv1beta1.ComponentType_TIKV,
		NodeSpecKey:   requestTikvSpecKey,
		ProjectId:     projectId,
	})
	if err != nil {
		return nil, nil, bizerr.WrapError(err, "failed to get tikv node spec")
	}
	if requestTiflashSpecKey != "" {
		desiredTiflashSpec, err = regionSvc.GetNodeSpecForPrice(ctx, &openapidedicatedv1beta1.GetNodeSpecRequest{
			RegionId:      openapiRegionId,
			ComponentType: openapidedicatedv1beta1.ComponentType_TIFLASH,
			NodeSpecKey:   requestTiflashSpecKey,
			ProjectId:     projectId,
		})
		if err != nil {
			return nil, nil, bizerr.WrapError(err, "failed to get tiflash node spec")
		}
	}
	return desiredTikvSpec, desiredTiflashSpec, nil
}

// GetCreateNodeSpecs gets the TiKV and TiFlash node specs for creating a dedicated cluster.
func GetCreateNodeSpecs(
	ctx context.Context,
	regionSvc openapidedicatedv1beta1.RegionServiceServer,
	openapiRegionId, requestTikvSpecKey, requestTiflashSpecKey, projectId, version string,
) (desiredTikvSpec, desiredTiflashSpec *openapidedicatedv1beta1.NodeSpec, _ bizerr.BizError) {
	desiredTikvSpec, err := regionSvc.GetNodeSpec(ctx, &openapidedicatedv1beta1.GetNodeSpecRequest{
		RegionId:      openapiRegionId,
		ComponentType: openapidedicatedv1beta1.ComponentType_TIKV,
		NodeSpecKey:   requestTikvSpecKey,
		ProjectId:     projectId,
		Condition: &openapidedicatedv1beta1.GetNodeSpecRequest_TidbVersion{
			TidbVersion: version,
		},
	})
	if err != nil {
		return nil, nil, bizerr.WrapError(err, "failed to get tikv node spec")
	}
	if requestTiflashSpecKey != "" {
		desiredTiflashSpec, err = regionSvc.GetNodeSpec(ctx, &openapidedicatedv1beta1.GetNodeSpecRequest{
			RegionId:      openapiRegionId,
			ComponentType: openapidedicatedv1beta1.ComponentType_TIFLASH,
			NodeSpecKey:   requestTiflashSpecKey,
			ProjectId:     projectId,
			Condition: &openapidedicatedv1beta1.GetNodeSpecRequest_TidbVersion{
				TidbVersion: version,
			},
		})
		if err != nil {
			return nil, nil, bizerr.WrapError(err, "failed to get tiflash node spec")
		}
	}
	return desiredTikvSpec, desiredTiflashSpec, nil
}

// GetUpdateNodeSpecs gets the TiKV and TiFlash node specs for updating a dedicated cluster.
func GetUpdateNodeSpecs(
	ctx context.Context,
	regionSvc openapidedicatedv1beta1.RegionServiceServer,
	requestTikvSpecKey, requestTiflashSpecKey, projectId string,
	globalCluster *globaldedicatedv1.Cluster,
) (desiredTikvSpec, desiredTiflashSpec *openapidedicatedv1beta1.NodeSpec, _ bizerr.BizError) {
	_, regionId, _, err := common.BuildOpenApiRegionName(globalCluster.GetCloudProviderId().String(), globalCluster.GetRegionId().String())
	if err != nil {
		return nil, nil, bizerr.WrapError(err, "invalid region info from cluster")
	}
	currentTikvComponent, _ := lo.Find(globalCluster.GetClusterComponents(), func(i *globaldedicatedv1.Cluster_ClusterComponent) bool {
		return i.GetComponentType() == globaldedicatedv1.ComponentType_TIKV
	})
	desiredTikvSpec, err = regionSvc.GetNodeSpec(ctx, &openapidedicatedv1beta1.GetNodeSpecRequest{
		RegionId:      regionId,
		ComponentType: openapidedicatedv1beta1.ComponentType_TIKV,
		NodeSpecKey:   lo.CoalesceOrEmpty(requestTikvSpecKey, currentTikvComponent.GetSpuName()),
		ProjectId:     projectId,
		Condition: &openapidedicatedv1beta1.GetNodeSpecRequest_ClusterId{
			ClusterId: strconv.FormatUint(globalCluster.GetClusterId(), 10),
		},
	})
	if err != nil {
		return nil, nil, bizerr.WrapError(err, "failed to get tikv node spec")
	}
	currentTiflashComponent, _ := lo.Find(globalCluster.GetClusterComponents(), func(i *globaldedicatedv1.Cluster_ClusterComponent) bool {
		return i.GetComponentType() == globaldedicatedv1.ComponentType_TIFLASH
	})
	desiredTiflashSpecKey := lo.CoalesceOrEmpty(requestTiflashSpecKey, currentTiflashComponent.GetSpuName())
	if desiredTiflashSpecKey != "" {
		desiredTiflashSpec, err = regionSvc.GetNodeSpec(ctx, &openapidedicatedv1beta1.GetNodeSpecRequest{
			RegionId:      regionId,
			ComponentType: openapidedicatedv1beta1.ComponentType_TIFLASH,
			NodeSpecKey:   desiredTiflashSpecKey,
			ProjectId:     projectId,
			Condition: &openapidedicatedv1beta1.GetNodeSpecRequest_ClusterId{
				ClusterId: strconv.FormatUint(globalCluster.GetClusterId(), 10),
			},
		})
		if err != nil {
			return nil, nil, bizerr.WrapError(err, "failed to get tiflash node spec")
		}
	}
	return desiredTikvSpec, desiredTiflashSpec, nil
}
