package cluster

import (
	"context"
	"strconv"
	"time"

	openapiserverlessv1beta1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/serverless/v1beta1"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/grpc/metadata"
)

func (c serverImpl) BatchDeleteClusters(
	ctx context.Context,
	request *openapiserverlessv1beta1.BatchDeleteClustersRequest,
) (resp *openapiserverlessv1beta1.BatchDeleteClustersResponse, err error) {
	tenantID := unknownTenantID
	startTime := time.Now()
	defer func() {
		recordWriteClusterAPIMetrics(apiBatchDeleteClusters, tenantID, time.Since(startTime).Seconds(), err)
	}()

	reqMeta, err := metadata.ExtractRequestMetaWithCheckPermission(ctx)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "failed to extract request metadata")
	}
	tenantID = strconv.FormatUint(reqMeta.OrgID, 10)

	if len(request.GetClusterIds()) == 0 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "cluster ids must not be empty")
	}

	if len(request.GetClusterIds()) > maxBatchSize {
		return nil, bizerr.New(bizerr.ErrCodeParams, "too many cluster ids, max=%d", maxBatchSize)
	}

	uniqueClusterIDs := make([]string, 0, len(request.GetClusterIds()))
	parsedClusterIDs := make(map[string]uint64, len(request.GetClusterIds()))
	seenClusterIDs := make(map[uint64]struct{}, len(request.GetClusterIds()))

	for _, clusterID := range request.GetClusterIds() {
		parsedID, parseErr := strconv.ParseUint(clusterID, 10, 64)
		if parseErr != nil {
			return nil, bizerr.WrapErrorWithCode(parseErr, bizerr.ErrCodeParams, "invalid cluster id: %s", clusterID)
		}

		if _, ok := seenClusterIDs[parsedID]; ok {
			continue
		}
		seenClusterIDs[parsedID] = struct{}{}

		parsedClusterIDs[clusterID] = parsedID
		uniqueClusterIDs = append(uniqueClusterIDs, clusterID)
	}

	response := &openapiserverlessv1beta1.BatchDeleteClustersResponse{
		Total:             int32(len(uniqueClusterIDs)),
		SuccessClusterIds: make([]string, 0, len(uniqueClusterIDs)),
		FailedClusterIds:  make([]string, 0),
	}

	for _, clusterID := range uniqueClusterIDs {
		clusterCtx := metadata.AppendToIncomingMeta(ctx, &metadata.RequestMeta{
			OrgID:             reqMeta.OrgID,
			DefaultProjectID:  reqMeta.DefaultProjectID,
			UserID:            reqMeta.UserID,
			Email:             reqMeta.Email,
			ApiPublicKey:      reqMeta.ApiPublicKey,
			ApiPublicKeyId:    reqMeta.ApiPublicKeyId,
			AccessToken:       reqMeta.AccessToken,
			ValidProjectList:  reqMeta.ValidProjectList,
			IsCheckPermission: reqMeta.IsCheckPermission,
			ClusterID:         parsedClusterIDs[clusterID],
		})

		_, deleteErr := c.DeleteCluster(clusterCtx, &openapiserverlessv1beta1.DeleteClusterRequest{ClusterId: clusterID})
		if deleteErr != nil {
			response.FailedClusterIds = append(response.FailedClusterIds, clusterID)
			continue
		}

		response.SuccessClusterIds = append(response.SuccessClusterIds, clusterID)
	}

	resp = response
	return resp, nil
}
