package errs

import (
	"strings"

	"backend/pkg/library/errors/code"
)

/* =========================
   日誌介面（與你現有 Logger 對齊）
   ========================= */

// Logger 你現有的 logger 介面（與外部一致即可）
type Logger interface {
	WithCallerSkip(n int) Logger
	WithFields(fields ...LogField) Logger
	Error(msg string)
	Warn(msg string)
	Info(msg string)
}

// LogField 結構化欄位
type LogField struct {
	Key string
	Val any
}

/* =========================
   共用小工具
   ========================= */

// joinMsg：把可變參數字串用空白串接（避免到處判斷 nil / 空 slice）
func joinMsg(s []string) string {
	if len(s) == 0 {
		return ""
	}

	return strings.Join(s, " ")
}

// logErr：統一打一筆 error log（避免重複記錄）
func logErr(l Logger, fields []LogField, e *Error) {
	if l == nil || e == nil {
		return
	}
	ll := l.WithCallerSkip(1)
	if len(fields) > 0 {
		ll = ll.WithFields(fields...)
	}
	// 需要更多欄位可在此擴充，例如：e.DisplayCode()、e.Category()、e.Detail()
	ll.Error(e.Error())
}

/* =========================
   共用裝飾器（把任意 ez 建構器包成帶日誌版本）
   ========================= */

// WithLog 將任一 *Error 建構器（如 SysTimeoutError）轉成帶日誌的版本
func WithLog(l Logger, fields []LogField, ctor func(s ...string) *Error, s ...string) *Error {
	e := ctor(s...)
	logErr(l, fields, e)

	return e
}

// WithLogWrap 同上，但會同時 Wrap 內部 cause
func WithLogWrap(l Logger, fields []LogField, ctor func(s ...string) *Error, cause error, s ...string) *Error {
	e := ctor(s...).Wrap(cause)
	logErr(l, fields, e)

	return e
}

/* =========================
   泛用建構器（當你懶得記函式名時）
   ========================= */

// EL 依 Category/Detail 直接建構並記錄日誌
func EL(l Logger, fields []LogField, cat code.Category, det code.Detail, s ...string) *Error {
	e := New(uint32(Scope), uint32(cat), uint32(det), joinMsg(s))
	logErr(l, fields, e)

	return e
}

// ELWrap 同上，並 Wrap cause
func ELWrap(l Logger, fields []LogField, cat code.Category, det code.Detail, cause error, s ...string) *Error {
	e := New(uint32(Scope), uint32(cat), uint32(det), joinMsg(s)).Wrap(cause)
	logErr(l, fields, e)

	return e
}

/* =======================================================================
   一、基礎 ez 建構器（純建構 *Error，不帶日誌）
   分類順序：Input → DB → Resource → Auth → System → PubSub → Service
   ======================================================================= */

/* ----- Input (CatInput) ----- */

func InputInvalidFormatError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.InputInvalidFormat), 0, joinMsg(s))
}
func InputNotValidImplementationError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.InputNotValidImplementation), 0, joinMsg(s))
}
func InputInvalidRangeError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.InputInvalidRange), 0, joinMsg(s))
}

/* ----- DB (CatDB) ----- */

func DBErrorError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.DBError), 0, joinMsg(s))
}
func DBDataConvertError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.DBDataConvert), 0, joinMsg(s))
}
func DBDuplicateError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.DBDuplicate), 0, joinMsg(s))
}

/* ----- Resource (CatResource) ----- */

func ResNotFoundError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.ResNotFound), 0, joinMsg(s))
}
func ResInvalidFormatError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.ResInvalidFormat), 0, joinMsg(s))
}
func ResAlreadyExistError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.ResAlreadyExist), 0, joinMsg(s))
}
func ResInsufficientError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.ResInsufficient), 0, joinMsg(s))
}
func ResInsufficientPermError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.ResInsufficientPerm), 0, joinMsg(s))
}
func ResInvalidMeasureIDError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.ResInvalidMeasureID), 0, joinMsg(s))
}
func ResExpiredError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.ResExpired), 0, joinMsg(s))
}
func ResMigratedError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.ResMigrated), 0, joinMsg(s))
}
func ResInvalidStateError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.ResInvalidState), 0, joinMsg(s))
}
func ResInsufficientQuotaError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.ResInsufficientQuota), 0, joinMsg(s))
}
func ResMultiOwnerError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.ResMultiOwner), 0, joinMsg(s))
}

/* ----- Auth (CatAuth) ----- */

func AuthUnauthorizedError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.AuthUnauthorized), 0, joinMsg(s))
}
func AuthExpiredError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.AuthExpired), 0, joinMsg(s))
}
func AuthInvalidPosixTimeError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.AuthInvalidPosixTime), 0, joinMsg(s))
}
func AuthSigPayloadMismatchError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.AuthSigPayloadMismatch), 0, joinMsg(s))
}
func AuthForbiddenError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.AuthForbidden), 0, joinMsg(s))
}

/* ----- System (CatSystem) ----- */

func SysInternalError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.SysInternal), 0, joinMsg(s))
}
func SysMaintainError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.SysMaintain), 0, joinMsg(s))
}
func SysTimeoutError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.SysTimeout), 0, joinMsg(s))
}
func SysTooManyRequestError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.SysTooManyRequest), 0, joinMsg(s))
}

/* ----- PubSub (CatPubSub) ----- */

func PSuPublishError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.PSuPublish), 0, joinMsg(s))
}
func PSuConsumeError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.PSuConsume), 0, joinMsg(s))
}
func PSuTooLargeError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.PSuTooLarge), 0, joinMsg(s))
}

/* ----- Service (CatService) ----- */

func SvcInternalError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.SvcInternal), 0, joinMsg(s))
}
func SvcThirdPartyError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.SvcThirdParty), 0, joinMsg(s))
}
func SvcHTTP400Error(s ...string) *Error {
	return New(uint32(Scope), uint32(code.SvcHTTP400), 0, joinMsg(s))
}
func SvcMaintenanceError(s ...string) *Error {
	return New(uint32(Scope), uint32(code.SvcMaintenance), 0, joinMsg(s))
}

/* =============================================================================
   二、帶日誌版本：L / WrapL（在「基礎 ez 建構器」之上包裝 WithLog / WithLogWrap）
   分類順序同上：Input → DB → Resource → Auth → System → PubSub → Service
   ============================================================================= */

/* ----- Input (CatInput) ----- */

func InputInvalidFormatErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, InputInvalidFormatError, s...)
}
func InputInvalidFormatErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, InputInvalidFormatError, cause, s...)
}

func InputNotValidImplementationErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, InputNotValidImplementationError, s...)
}
func InputNotValidImplementationErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, InputNotValidImplementationError, cause, s...)
}

func InputInvalidRangeErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, InputInvalidRangeError, s...)
}
func InputInvalidRangeErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, InputInvalidRangeError, cause, s...)
}

/* ----- DB (CatDB) ----- */

func DBErrorErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, DBErrorError, s...)
}
func DBErrorErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, DBErrorError, cause, s...)
}

func DBDataConvertErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, DBDataConvertError, s...)
}
func DBDataConvertErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, DBDataConvertError, cause, s...)
}

func DBDuplicateErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, DBDuplicateError, s...)
}
func DBDuplicateErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, DBDuplicateError, cause, s...)
}

/* ----- Resource (CatResource) ----- */

func ResNotFoundErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, ResNotFoundError, s...)
}
func ResNotFoundErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, ResNotFoundError, cause, s...)
}

func ResInvalidFormatErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, ResInvalidFormatError, s...)
}
func ResInvalidFormatErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, ResInvalidFormatError, cause, s...)
}

func ResAlreadyExistErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, ResAlreadyExistError, s...)
}
func ResAlreadyExistErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, ResAlreadyExistError, cause, s...)
}

func ResInsufficientErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, ResInsufficientError, s...)
}
func ResInsufficientErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, ResInsufficientError, cause, s...)
}

func ResInsufficientPermErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, ResInsufficientPermError, s...)
}
func ResInsufficientPermErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, ResInsufficientPermError, cause, s...)
}

func ResInvalidMeasureIDErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, ResInvalidMeasureIDError, s...)
}
func ResInvalidMeasureIDErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, ResInvalidMeasureIDError, cause, s...)
}

func ResExpiredErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, ResExpiredError, s...)
}
func ResExpiredErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, ResExpiredError, cause, s...)
}

func ResMigratedErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, ResMigratedError, s...)
}
func ResMigratedErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, ResMigratedError, cause, s...)
}

func ResInvalidStateErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, ResInvalidStateError, s...)
}
func ResInvalidStateErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, ResInvalidStateError, cause, s...)
}

func ResInsufficientQuotaErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, ResInsufficientQuotaError, s...)
}
func ResInsufficientQuotaErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, ResInsufficientQuotaError, cause, s...)
}

func ResMultiOwnerErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, ResMultiOwnerError, s...)
}
func ResMultiOwnerErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, ResMultiOwnerError, cause, s...)
}

/* ----- Auth (CatAuth) ----- */

func AuthUnauthorizedErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, AuthUnauthorizedError, s...)
}
func AuthUnauthorizedErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, AuthUnauthorizedError, cause, s...)
}

func AuthExpiredErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, AuthExpiredError, s...)
}
func AuthExpiredErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, AuthExpiredError, cause, s...)
}

func AuthInvalidPosixTimeErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, AuthInvalidPosixTimeError, s...)
}
func AuthInvalidPosixTimeErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, AuthInvalidPosixTimeError, cause, s...)
}

func AuthSigPayloadMismatchErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, AuthSigPayloadMismatchError, s...)
}
func AuthSigPayloadMismatchErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, AuthSigPayloadMismatchError, cause, s...)
}

func AuthForbiddenErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, AuthForbiddenError, s...)
}
func AuthForbiddenErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, AuthForbiddenError, cause, s...)
}

/* ----- System (CatSystem) ----- */

func SysInternalErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, SysInternalError, s...)
}
func SysInternalErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, SysInternalError, cause, s...)
}

func SysMaintainErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, SysMaintainError, s...)
}
func SysMaintainErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, SysMaintainError, cause, s...)
}

func SysTimeoutErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, SysTimeoutError, s...)
}
func SysTimeoutErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, SysTimeoutError, cause, s...)
}

func SysTooManyRequestErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, SysTooManyRequestError, s...)
}
func SysTooManyRequestErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, SysTooManyRequestError, cause, s...)
}

/* ----- PubSub (CatPubSub) ----- */

func PSuPublishErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, PSuPublishError, s...)
}
func PSuPublishErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, PSuPublishError, cause, s...)
}

func PSuConsumeErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, PSuConsumeError, s...)
}
func PSuConsumeErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, PSuConsumeError, cause, s...)
}

func PSuTooLargeErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, PSuTooLargeError, s...)
}
func PSuTooLargeErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, PSuTooLargeError, cause, s...)
}

/* ----- Service (CatService) ----- */

func SvcInternalErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, SvcInternalError, s...)
}
func SvcInternalErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, SvcInternalError, cause, s...)
}

func SvcThirdPartyErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, SvcThirdPartyError, s...)
}
func SvcThirdPartyErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, SvcThirdPartyError, cause, s...)
}

func SvcHTTP400ErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, SvcHTTP400Error, s...)
}
func SvcHTTP400ErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, SvcHTTP400Error, cause, s...)
}

func SvcMaintenanceErrorL(l Logger, fields []LogField, s ...string) *Error {
	return WithLog(l, fields, SvcMaintenanceError, s...)
}
func SvcMaintenanceErrorWrapL(l Logger, fields []LogField, cause error, s ...string) *Error {
	return WithLogWrap(l, fields, SvcMaintenanceError, cause, s...)
}
