package errs

import (
	"net/http"

	"github.com/tidbcloud/pkgv2/bizerr"
)

const (
	// codes defined in bizerr
	ErrCodeOK = int64(bizerr.ErrCodeOK)

	ErrCodeParams           = int64(bizerr.ErrCodeParams)
	ErrCodeAuth             = int64(bizerr.ErrCodeAuth)
	ErrCodePermission       = int64(bizerr.ErrCodePermission)
	ErrCodeRecordNotFound   = int64(bizerr.ErrCodeRecordNotFound)
	ErrCodeRecordExist      = int64(bizerr.ErrCodeRecordExist)
	ErrCodeIPBlocked        = int64(bizerr.ErrCodeIPBlocked)        // HTTP 403
	ErrCodeTooManyRequests  = int64(bizerr.ErrCodeTooManyRequests)  // HTTP 429
	ErrCodeUnderMaintenance = int64(bizerr.ErrCodeUnderMaintenance) // HTTP 403

	ErrCodeDB               = int64(bizerr.ErrCodeDB)
	ErrCodeRedis            = int64(bizerr.ErrCodeRedis)
	ErrCodeMQ               = int64(bizerr.ErrCodeMQ)
	ErrCodePanic            = int64(bizerr.ErrCodePanic)
	ErrCodeJsonMarshal      = int64(bizerr.ErrCodeJsonMarshal)
	ErrCodeTimeout          = int64(bizerr.ErrCodeTimeout)
	ErrCodeUnknown          = int64(bizerr.ErrCodeUnknown)
	ErrCodeHTTP             = int64(bizerr.ErrCodeHTTP)
	ErrCodeGRPC             = int64(bizerr.ErrCodeGRPC)
	ErrCodeSvcBilling       = int64(bizerr.ErrCodeSvcBilling)
	ErrCodeSvcInfraAPI      = int64(bizerr.ErrCodeSvcInfraAPI)
	ErrCodeSvcInfraMetering = int64(bizerr.ErrCodeSvcInfraMetering)

	ErrCodeGeneralBusiness        = int64(bizerr.ErrCodeGeneralBusiness)        // general business error
	ErrCodeOptimisticLockConflict = int64(bizerr.ErrCodeOptimisticLockConflict) // optimistic lock conflict
	// end here
)

var (
	// alias
	ErrCodeBadRequest   = ErrCodeParams
	ErrCodeUnauthorized = ErrCodeAuth
	ErrCodeForbidden    = ErrCodePermission
	ErrCodeNotFound     = ErrCodeRecordNotFound

	// codes defined in errs, ref: https://github.com/golang/go/blob/master/src/net/http/status.go#L9
	ErrCodePaymentRequired       = convertFromHTTPCode(http.StatusPaymentRequired)
	ErrCodeMethodNotAllowed      = convertFromHTTPCode(http.StatusMethodNotAllowed)
	ErrCodeNotAcceptable         = convertFromHTTPCode(http.StatusNotAcceptable)
	ErrCodeRequestTimeout        = convertFromHTTPCode(http.StatusRequestTimeout)
	ErrCodeConflict              = convertFromHTTPCode(http.StatusConflict)
	ErrCodeLengthRequired        = convertFromHTTPCode(http.StatusLengthRequired)
	ErrCodePreconditionFailed    = convertFromHTTPCode(http.StatusPreconditionFailed)
	ErrCodeRequestEntityTooLarge = convertFromHTTPCode(http.StatusRequestEntityTooLarge)
	ErrCodeRequestURITooLong     = convertFromHTTPCode(http.StatusRequestURITooLong)
	ErrCodeUnsupportedMediaType  = convertFromHTTPCode(http.StatusUnsupportedMediaType)
	ErrCodeExpectationFailed     = convertFromHTTPCode(http.StatusExpectationFailed)

	ErrCodeInternalServerError = convertFromHTTPCode(http.StatusInternalServerError)
	ErrCodeNotImplemented      = convertFromHTTPCode(http.StatusNotImplemented)
	ErrCodeBadGateway          = convertFromHTTPCode(http.StatusBadGateway)
	ErrCodeServiceUnavailable  = convertFromHTTPCode(http.StatusServiceUnavailable)
)

const bizErrorKeyHttpCode = "TiError_HTTP_CODE"
const bizErrorKeyOrigErrMsg = "TiError_ORIG_ERR_MSG"
const defaultBizErrorHttpCode = 500

func convertFromHTTPCode(code int) int64 {
	// follow rules from bizerr, client err startswith 499 and 5 digits code, server error startswith 599 and 5 digits
	if code >= http.StatusBadRequest && code < http.StatusInternalServerError {
		return int64(49900000 + code)
	} else if code >= http.StatusInternalServerError {
		return int64(59900000 + code)
	} else {
		return 0
	}
}
