package exerr

import (
	"gogs.mikescher.com/BlackForestBytes/goext/dataext"
	"gogs.mikescher.com/BlackForestBytes/goext/langext"
)

type ErrorCategory struct{ Category string }

var (
	CatWrap    = ErrorCategory{"Wrap"}    // The error is simply wrapping another error (e.g. when a grpc call returns an error)
	CatSystem  = ErrorCategory{"System"}  // An internal system error (e.g. connection to db failed)
	CatUser    = ErrorCategory{"User"}    // The user (the API caller) did something wrong (e.g. he has no permissions to do this)
	CatForeign = ErrorCategory{"Foreign"} // A foreign error that some component threw (e.g. an unknown mongodb error), happens if we call Wrap(..) on an non-bmerror value
)

//goland:noinspection GoUnusedGlobalVariable
var AllCategories = []ErrorCategory{CatWrap, CatSystem, CatUser, CatForeign}

type ErrorSeverity struct{ Severity string }

var (
	SevTrace = ErrorSeverity{"Trace"}
	SevDebug = ErrorSeverity{"Debug"}
	SevInfo  = ErrorSeverity{"Info"}
	SevWarn  = ErrorSeverity{"Warn"}
	SevErr   = ErrorSeverity{"Err"}
	SevFatal = ErrorSeverity{"Fatal"}
)

//goland:noinspection GoUnusedGlobalVariable
var AllSeverities = []ErrorSeverity{SevTrace, SevDebug, SevInfo, SevWarn, SevErr, SevFatal}

type ErrorType struct {
	Key               string
	DefaultStatusCode *int
}

//goland:noinspection GoUnusedGlobalVariable
var (
	TypeInternal       = NewType("INTERNAL_ERROR", langext.Ptr(500))
	TypePanic          = NewType("PANIC", langext.Ptr(500))
	TypeNotImplemented = NewType("NOT_IMPLEMENTED", langext.Ptr(500))

	TypeMongoQuery        = NewType("MONGO_QUERY", langext.Ptr(500))
	TypeCursorTokenDecode = NewType("CURSOR_TOKEN_DECODE", langext.Ptr(500))
	TypeMongoFilter       = NewType("MONGO_FILTER", langext.Ptr(500))
	TypeMongoReflection   = NewType("MONGO_REFLECTION", langext.Ptr(500))
	TypeMongoInvalidOpt   = NewType("MONGO_INVALIDOPT", langext.Ptr(500))

	TypeSQLQuery  = NewType("SQL_QUERY", langext.Ptr(500))
	TypeSQLBuild  = NewType("SQL_BUILD", langext.Ptr(500))
	TypeSQLDecode = NewType("SQL_DECODE", langext.Ptr(500))

	TypeWrap = NewType("Wrap", nil)

	TypeBindFailURI      = NewType("BINDFAIL_URI", langext.Ptr(400))
	TypeBindFailQuery    = NewType("BINDFAIL_QUERY", langext.Ptr(400))
	TypeBindFailJSON     = NewType("BINDFAIL_JSON", langext.Ptr(400))
	TypeBindFailFormData = NewType("BINDFAIL_FORMDATA", langext.Ptr(400))
	TypeBindFailHeader   = NewType("BINDFAIL_HEADER", langext.Ptr(400))

	TypeMarshalEntityID = NewType("MARSHAL_ENTITY_ID", langext.Ptr(400))
	TypeInvalidCSID     = NewType("INVALID_CSID", langext.Ptr(400))

	TypeGoogleStatuscode = NewType("GOOGLE_STATUSCODE", langext.Ptr(400))
	TypeGoogleResponse   = NewType("GOOGLE_RESPONSE", langext.Ptr(400))

	TypeUnauthorized = NewType("UNAUTHORIZED", langext.Ptr(401))
	TypeAuthFailed   = NewType("AUTH_FAILED", langext.Ptr(401))

	// other values come from the downstream application that uses goext
)

var registeredTypes = dataext.SyncMap[string, ErrorType]{}

func NewType(key string, defStatusCode *int) ErrorType {
	et := ErrorType{key, defStatusCode}

	registeredTypes.Set(key, et)

	return et
}

func ListRegisteredTypes() []ErrorType {
	return registeredTypes.GetAllValues()
}

type LogPrintLevel string

const (
	LogPrintFull     LogPrintLevel = "Full"
	LogPrintOverview LogPrintLevel = "Overview"
	LogPrintShort    LogPrintLevel = "Short"
)