package cluster

import (
	"context"
	"errors"
	"strconv"

	"github.com/tidbcloud/tiinf/sdk/auditlog"
	"gorm.io/gorm"

	openapidedicatedv1beta1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/dedicated/v1beta1"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/adapter/eventbus"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/constant"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/entity"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/pkg/apimiddleware/bizerror"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/grpc/metadata"
)

func (c *serverImpl) PauseCluster(
	ctx context.Context,
	req *openapidedicatedv1beta1.PauseClusterRequest,
) (*openapidedicatedv1beta1.PauseClusterResponse, error) {
	ctx, span := tracer.Start(ctx, "PauseCluster")
	defer span.End()
	var (
		err     error
		reqMeta *metadata.RequestMeta
		res     *openapidedicatedv1beta1.Cluster
	)

	detailsFunc := func() auditlog.Details {
		details := eventbus.NewAuditLogDetails(eventbus.TierTypeDedicated)
		details = eventbus.AppendDedicatedClusterDetails(details, res)
		return details
	}
	defer func() {
		c.auditLogSender.SubmitAuditLog(ctx, auditlog.EventPauseCluster, reqMeta, detailsFunc, err)
	}()

	// Extract request meta.
	reqMeta, err = metadata.ExtractRequestMetaWithCheckPermission(ctx)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "failed to extract request metadata")
	}

	var clusterId uint64
	clusterId, err = strconv.ParseUint(req.ClusterId, 10, 64)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "invalid cluster id")
	}

	// Pause from domain service
	var (
		customStatus *entity.ClusterCustomStatus
		cluster      *entity.Cluster
	)
	cluster, customStatus, err = c.clusterSvc.PauseCluster(ctx, clusterId)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, bizerror.NewNotFound(err, "cluster not found")
		} else if errors.Is(err, constant.ErrClusterCustomStatusForbidden) {
			return nil, bizerror.NewForbiddenForClusterCustomStatus(err, customStatus.StatusType.String())
		}
		return nil, err
	}

	res, err = buildClusterFromEntity(cluster, nil)
	if err != nil {
		return nil, bizerror.NewInternal(err, "failed to get cluster")
	}

	return &openapidedicatedv1beta1.PauseClusterResponse{Cluster: res}, nil
}
