package utils

import (
	"crypto/aes"
	"encoding/base64"
	"fmt"
	"strconv"
	"strings"
)

type ErrorWithCode struct {
	level      int
	prefixList []string
	errMsg     string
	code       string
	intCode    int
}

func NewErrorCode(errMsg, code string, level ...int) *ErrorWithCode {
	retVal := &ErrorWithCode{
		errMsg: errMsg,
		code:   code,
	}
	retVal.intCode, _ = strconv.Atoi(code)
	if len(level) > 0 {
		retVal.level = level[0]
	}

	return retVal
}

func DecryptDESECB(d, key []byte) string {
	data, err := base64.StdEncoding.DecodeString(string(d))
	if err != nil {
		return ""
	}
	block, err := aes.NewCipher(key)
	if err != nil {
		return ""
	}
	bs := block.BlockSize()
	if len(data)%bs != 0 {
		return ""
	}
	out := make([]byte, len(data))
	dst := out
	for len(data) > 0 {
		block.Decrypt(dst, data[:bs])
		data = data[bs:]
		dst = dst[bs:]
	}
	out = PKCS5UnPadding(out)
	return string(out)
}
func PKCS5UnPadding(origData []byte) []byte {
	length := len(origData)
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}

func NewErrorIntCode(errMsg string, code int, level ...int) *ErrorWithCode {
	return NewErrorCode(errMsg, Int2Str(code), level...)
}

func (e *ErrorWithCode) Error() string {
	fullErrMsg := e.ErrMsg()
	if len(e.prefixList) > 0 {
		fullErrMsg = strings.Join(e.prefixList, ",") + ", " + fullErrMsg
	}
	return fmt.Sprintf("%s level:%d, code:%s", fullErrMsg, e.Level(), e.Code())
}

func (e *ErrorWithCode) String() string {
	return e.Error()
}

func (e *ErrorWithCode) Level() int {
	return e.level
}

func (e *ErrorWithCode) Code() string {
	return e.code
}

func (e *ErrorWithCode) IntCode() int {
	return e.intCode
}

func (e *ErrorWithCode) ErrMsg() string {
	return e.errMsg
}

func (e *ErrorWithCode) SetErrMsg(errMsg string) {
	e.errMsg = errMsg
}

func (e *ErrorWithCode) AddPrefixMsg(prefix string) {
	e.prefixList = append(e.prefixList, prefix)
}

func IsErrMatch(err error, strCode string, strList []string) (isMatch bool) {
	if err != nil {
		if codeErr, ok := err.(*ErrorWithCode); ok {
			if strCode == "" || codeErr.Code() == strCode {
				isMatch = IsErrMsgMatch(codeErr.ErrMsg(), strList)
			}
		}
	}
	return isMatch
}

func IsErrMsgMatch(errMsg string, strList []string) (isMatch bool) {
	isMatch = len(strList) == 0
	for _, v := range strList {
		if strings.Index(errMsg, v) >= 0 {
			isMatch = true
			break
		}
	}
	return isMatch
}

func GetErrMsg(err error) (errMsg string) {
	if errExt, ok := err.(*ErrorWithCode); ok {
		errMsg = errExt.ErrMsg()
	}
	return errMsg
}
