package bizerror

import (
	"fmt"
	"strings"

	"braces.dev/errtrace"
	"google.golang.org/genproto/googleapis/rpc/errdetails"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

// https://pingcap.feishu.cn/wiki/HNO3wDfesiMqr1kPGTrc1dPrnNf
//
// All errors generated here are ***grpc status errors***.

func NewForbiddenForClusterCustomStatus(err error, state string) error {
	state = strings.TrimPrefix(state, "CUSTOM_STATUS_TYPE_")
	return NewError(
		err,
		bizerr.ErrCodePermission,
		fmt.Sprintf("Forbidden. The cluster is in the %s state and cannot execute this operation.", state),
	)
}

func NewDisplayNameAlreadyExists(err error) error {
	return NewError(err, bizerr.ErrCodeDuplicateDisplayName, bizerr.ErrMsgDupDisplayName)
}

func NewNotFound(err error, msg string) error {
	return NewError(err, bizerr.ErrCodeRecordNotFound, msg)
}

func NewInternal(err error, msg string) error {
	return NewError(err, bizerr.GeneralInternalErrorCode, msg)
}

func NewError(err error, code bizerr.ErrCode, msg string) error {
	s := status.New(codes.Code(code), prettifyErrMsg(msg))

	// Enrich error details with DebugInfo
	debugInfo := &errdetails.DebugInfo{
		Detail: errtrace.FormatString(err),
	}

	var e error
	if s, e = s.WithDetails(debugInfo); e != nil {
		return status.Error(
			codes.Code(bizerr.GeneralInternalErrorCode),
			"build error response: failed to add error details",
		)
	}

	return s.Err()
}

// remove duplicate grpc error msg desc
func prettifyErrMsg(msg string) string {
	if strings.Contains(msg, "desc = ") {
		er := strings.Split(msg, "desc =")
		msg = er[len(er)-1]
	}

	// remove space
	msg = strings.TrimSpace(msg)
	return msg
}
