package errors

import (
	"errors"
	"fmt"
)

// 中间件标准错误类型
var (
	ErrMissingToken     = errors.New("missing authentication token")
	ErrInvalidToken     = errors.New("invalid or expired token")
	ErrRedisUnavailable = errors.New("redis unavailable")
	ErrTooManyRequests  = errors.New("too many requests")
)

// 预定义业务错误（常用错误可直接引用）
var (
	ErrAssetAllocationRecordNotFound = &AppError{Code: CodeAssetAllocationRecordNotFound, Message: "分配记录不存在"}
	ErrNotDirectSubordinate          = &AppError{Code: CodeNotDirectSubordinate, Message: "只能操作直属下级店铺"}
	ErrIotCardBoundToDevice          = &AppError{Code: CodeIotCardBoundToDevice, Message: "IoT 卡已绑定设备，不能单独操作"}
	ErrIotCardStatusNotAllowed       = &AppError{Code: CodeIotCardStatusNotAllowed, Message: "卡状态不允许此操作"}
	ErrCannotAllocateToSelf          = &AppError{Code: CodeCannotAllocateToSelf, Message: "不能分配给自己"}
	ErrCannotRecallFromSelf          = &AppError{Code: CodeCannotRecallFromSelf, Message: "不能从自己回收"}
)

// AppError 表示带错误码的应用错误
type AppError struct {
	Code    int    // 应用错误码
	Message string // 错误消息
	Err     error  // 底层错误（可选）
}

func (e *AppError) Error() string {
	if e.Err != nil {
		return fmt.Sprintf("%s: %v", e.Message, e.Err)
	}
	return e.Message
}

func (e *AppError) Unwrap() error {
	return e.Err
}

// New 创建新的 AppError
// 优先使用 errorMessages 映射表中的消息，允许通过可选参数覆盖
// 用法：
//   - errors.New(errors.CodeNotFound)                    // 使用映射表默认消息
//   - errors.New(errors.CodeNotFound, "提现申请不存在")  // 覆盖为自定义消息
func New(code int, customMsg ...string) *AppError {
	// 默认从映射表获取消息
	message := GetMessage(code, "zh-CN")
	// 如果提供了自定义消息且非空，则覆盖
	if len(customMsg) > 0 && customMsg[0] != "" {
		message = customMsg[0]
	}
	return &AppError{
		Code:    code,
		Message: message,
	}
}

// Wrap 用错误码和消息包装现有错误
// 优先使用 errorMessages 映射表中的消息，允许通过可选参数覆盖
// 用法：
//   - errors.Wrap(errors.CodeDatabaseError, originalErr)                    // 使用映射表默认消息
//   - errors.Wrap(errors.CodeDatabaseError, originalErr, "查询用户失败")    // 覆盖为自定义消息
func Wrap(code int, err error, customMsg ...string) *AppError {
	message := GetMessage(code, "zh-CN")
	if len(customMsg) > 0 && customMsg[0] != "" {
		message = customMsg[0]
	}
	return &AppError{
		Code:    code,
		Message: message,
		Err:     err,
	}
}
