package errs

import (
	"strings"

	"gateway/internal/library/errors/code"
)

// Builder constructs *Error values for a fixed scope.
type Builder struct {
	scope code.Scope
}

// Scope returns the builder's scope.
func (b Builder) Scope() code.Scope {
	return b.scope
}

// Code builds an error from category, detail, and an optional message.
func (b Builder) Code(category code.Category, detail code.Detail, msg ...string) *Error {
	return b.must(category, detail, joinMsg(msg))
}

func (b Builder) must(category code.Category, detail code.Detail, msg string) *Error {
	return MustNew(b.scope, category, detail, msg)
}

func joinMsg(parts []string) string {
	if len(parts) == 0 {
		return ""
	}

	return strings.Join(parts, " ")
}

/* ----- Input ----- */

func (b Builder) InputInvalidFormat(msg ...string) *Error {
	return b.must(code.InputInvalidFormat, 0, joinMsg(msg))
}

func (b Builder) InputNotValidImplementation(msg ...string) *Error {
	return b.must(code.InputNotValidImplementation, 0, joinMsg(msg))
}

func (b Builder) InputInvalidRange(msg ...string) *Error {
	return b.must(code.InputInvalidRange, 0, joinMsg(msg))
}

func (b Builder) InputMissingRequired(msg ...string) *Error {
	return b.must(code.InputMissingRequired, 0, joinMsg(msg))
}

func (b Builder) InputUnsupportedMedia(msg ...string) *Error {
	return b.must(code.InputUnsupportedMedia, 0, joinMsg(msg))
}

func (b Builder) InputPayloadTooLarge(msg ...string) *Error {
	return b.must(code.InputPayloadTooLarge, 0, joinMsg(msg))
}

/* ----- DB ----- */

func (b Builder) DBError(msg ...string) *Error {
	return b.must(code.DBError, 0, joinMsg(msg))
}

func (b Builder) DBDataConvert(msg ...string) *Error {
	return b.must(code.DBDataConvert, 0, joinMsg(msg))
}

func (b Builder) DBDuplicate(msg ...string) *Error {
	return b.must(code.DBDuplicate, 0, joinMsg(msg))
}

func (b Builder) DBUnavailable(msg ...string) *Error {
	return b.must(code.DBUnavailable, 0, joinMsg(msg))
}

/* ----- Resource ----- */

func (b Builder) ResNotFound(msg ...string) *Error {
	return b.must(code.ResNotFound, 0, joinMsg(msg))
}

func (b Builder) ResInvalidFormat(msg ...string) *Error {
	return b.must(code.ResInvalidFormat, 0, joinMsg(msg))
}

func (b Builder) ResAlreadyExist(msg ...string) *Error {
	return b.must(code.ResAlreadyExist, 0, joinMsg(msg))
}

func (b Builder) ResInsufficient(msg ...string) *Error {
	return b.must(code.ResInsufficient, 0, joinMsg(msg))
}

func (b Builder) ResInsufficientPerm(msg ...string) *Error {
	return b.must(code.ResInsufficientPerm, 0, joinMsg(msg))
}

func (b Builder) ResInvalidMeasureID(msg ...string) *Error {
	return b.must(code.ResInvalidMeasureID, 0, joinMsg(msg))
}

func (b Builder) ResExpired(msg ...string) *Error {
	return b.must(code.ResExpired, 0, joinMsg(msg))
}

func (b Builder) ResMigrated(msg ...string) *Error {
	return b.must(code.ResMigrated, 0, joinMsg(msg))
}

func (b Builder) ResInvalidState(msg ...string) *Error {
	return b.must(code.ResInvalidState, 0, joinMsg(msg))
}

func (b Builder) ResInsufficientQuota(msg ...string) *Error {
	return b.must(code.ResInsufficientQuota, 0, joinMsg(msg))
}

func (b Builder) ResMultiOwner(msg ...string) *Error {
	return b.must(code.ResMultiOwner, 0, joinMsg(msg))
}

func (b Builder) ResPreconditionFailed(msg ...string) *Error {
	return b.must(code.ResPreconditionFailed, 0, joinMsg(msg))
}

func (b Builder) ResLocked(msg ...string) *Error {
	return b.must(code.ResLocked, 0, joinMsg(msg))
}

/* ----- Auth ----- */

func (b Builder) AuthUnauthorized(msg ...string) *Error {
	return b.must(code.AuthUnauthorized, 0, joinMsg(msg))
}

func (b Builder) AuthExpired(msg ...string) *Error {
	return b.must(code.AuthExpired, 0, joinMsg(msg))
}

func (b Builder) AuthInvalidPosixTime(msg ...string) *Error {
	return b.must(code.AuthInvalidPosixTime, 0, joinMsg(msg))
}

func (b Builder) AuthSigPayloadMismatch(msg ...string) *Error {
	return b.must(code.AuthSigPayloadMismatch, 0, joinMsg(msg))
}

func (b Builder) AuthForbidden(msg ...string) *Error {
	return b.must(code.AuthForbidden, 0, joinMsg(msg))
}

func (b Builder) AuthMethodNotAllowed(msg ...string) *Error {
	return b.must(code.AuthMethodNotAllowed, 0, joinMsg(msg))
}

/* ----- System ----- */

func (b Builder) SysInternal(msg ...string) *Error {
	return b.must(code.SysInternal, 0, joinMsg(msg))
}

func (b Builder) SysMaintain(msg ...string) *Error {
	return b.must(code.SysMaintain, 0, joinMsg(msg))
}

func (b Builder) SysTimeout(msg ...string) *Error {
	return b.must(code.SysTimeout, 0, joinMsg(msg))
}

func (b Builder) SysTooManyRequest(msg ...string) *Error {
	return b.must(code.SysTooManyRequest, 0, joinMsg(msg))
}

func (b Builder) SysNotImplemented(msg ...string) *Error {
	return b.must(code.SysNotImplemented, 0, joinMsg(msg))
}

func (b Builder) SysClientTimeout(msg ...string) *Error {
	return b.must(code.SysClientTimeout, 0, joinMsg(msg))
}

/* ----- PubSub ----- */

func (b Builder) PSuPublish(msg ...string) *Error {
	return b.must(code.PSuPublish, 0, joinMsg(msg))
}

func (b Builder) PSuConsume(msg ...string) *Error {
	return b.must(code.PSuConsume, 0, joinMsg(msg))
}

func (b Builder) PSuTooLarge(msg ...string) *Error {
	return b.must(code.PSuTooLarge, 0, joinMsg(msg))
}

/* ----- Service ----- */

func (b Builder) SvcInternal(msg ...string) *Error {
	return b.must(code.SvcInternal, 0, joinMsg(msg))
}

func (b Builder) SvcThirdParty(msg ...string) *Error {
	return b.must(code.SvcThirdParty, 0, joinMsg(msg))
}

func (b Builder) SvcHTTP400(msg ...string) *Error {
	return b.must(code.SvcHTTP400, 0, joinMsg(msg))
}

func (b Builder) SvcMaintenance(msg ...string) *Error {
	return b.must(code.SvcMaintenance, 0, joinMsg(msg))
}

func (b Builder) SvcRateLimited(msg ...string) *Error {
	return b.must(code.SvcRateLimited, 0, joinMsg(msg))
}
