package errno

import "fmt"

type Errno struct {
	Code    int
	Message string
}

func (err Errno) Error() string {
	return err.Message
}

// Err represents an error
type Err struct {
	Code    int
	Message string
	Err     error
}

func New(errno *Errno, err error) *Err {
	return &Err{Code: errno.Code, Message: errno.Message, Err: err}
}

func (err *Err) Add(message string) error {
	err.Message += " " + message
	return err
}

func (err *Err) Addf(format string, args ...interface{}) error {
	err.Message += " " + fmt.Sprintf(format, args...)
	return err
}

func (err *Err) Error() string {
	return fmt.Sprintf("Err - code: %d, message: %s, error: %s", err.Code, err.Message, err.Err)
}

func IsErrUserNotFound(err error) bool {
	code, _ := DecodeErr(err)
	return code == ErrUserNotFound.Code
}

func DecodeErr(err error) (int, string) {
	if err == nil {
		return OK.Code, OK.Message
	}

	switch typed := err.(type) {
	case *Err:
		return typed.Code, typed.Message
	case *Errno:
		return typed.Code, typed.Message
	default:
	}

	return InternalServerError.Code, err.Error()
}

var (
	// Common errors
	OK                  = &Errno{Code: 0, Message: "OK"}
	InternalServerError = &Errno{Code: 10001, Message: "Internal server error"}
	ErrBind             = &Errno{Code: 10002, Message: "Error occurred while binding the request body to the struct."}

	ErrValidation = &Errno{Code: 20001, Message: "Validation failed."}
	ErrDatabase   = &Errno{Code: 20002, Message: "Database error."}

	// coin errors
	ErrCoinNotFound = &Errno{Code: 20101, Message: "The coin was not found."}
	ErrCountCoin    = &Errno{Code: 20102, Message: "The coins statistic error."}
	ErrAddCoin      = &Errno{Code: 20101, Message: "The coin add error."}
	ErrUpdateCoin   = &Errno{Code: 20102, Message: "The coin update error."}
	ErrDeleteCoin   = &Errno{Code: 20102, Message: "The coin delete error."}
	ErrExistCoin    = &Errno{Code: 20103, Message: "The coin already exists."}
	ErrNotExistCoin = &Errno{Code: 20104, Message: "The coin not exists."}
	ErrAuthCoin = &Errno{Code: 20105, Message: "The coin auth error."}

	// recommend coin errors
	ErrRecommendCoinNotFound = &Errno{Code: 20101, Message: "The recommend coin was not found."}
	ErrCountRecommendCoin    = &Errno{Code: 20102, Message: "The recommend coins statistic error."}
	ErrAddRecommendCoin      = &Errno{Code: 20101, Message: "The recommend coin add error."}
	ErrUpdateRecommendCoin   = &Errno{Code: 20102, Message: "The recommend coin update error."}
	ErrDeleteRecommendCoin   = &Errno{Code: 20102, Message: "The recommend coin delete error."}
	ErrExistRecommendCoin    = &Errno{Code: 20103, Message: "The recommend coin already exists."}

	// wallet errors
	ErrWalletNotFound = &Errno{Code: 20101, Message: "The wallet was not found."}
	ErrCountWallet    = &Errno{Code: 20102, Message: "The wallets statistic error."}
	ErrAddWallet      = &Errno{Code: 20101, Message: "The wallet add error."}
	ErrUpdateWallet   = &Errno{Code: 20102, Message: "The wallet update error."}
	ErrDeleteWallet   = &Errno{Code: 20102, Message: "The wallet delete error."}

	// chain errors
	ErrChainNotFound = &Errno{Code: 20101, Message: "The chain was not found."}
	ErrCountChain    = &Errno{Code: 20102, Message: "The chain statistic error."}
	ErrAddChain      = &Errno{Code: 20101, Message: "The chain add error."}
	ErrUpdateChain   = &Errno{Code: 20102, Message: "The chain update error."}
	ErrDeleteChain   = &Errno{Code: 20102, Message: "The chain delete error."}

	// supported currency errors
	ErrSupportedCurrencyNotFound = &Errno{Code: 20101, Message: "The supported currency was not found."}
	ErrCountSupportedCurrency    = &Errno{Code: 20102, Message: "The supported currency statistic error."}
	ErrAddSupportedCurrency      = &Errno{Code: 20101, Message: "The supported currency add error."}
	ErrUpdateSupportedCurrency   = &Errno{Code: 20102, Message: "The supported currency update error."}
	ErrDeleteSupportedCurrency   = &Errno{Code: 20102, Message: "The supported currency delete error."}
	ErrExistSupportedCurrency    = &Errno{Code: 20103, Message: "The supported currency already exists."}

	// recommend category errors
	ErrRecommendCategoryNotFound = &Errno{Code: 20101, Message: "The recommend category was not found."}
	ErrCountRecommendCategory   = &Errno{Code: 20102, Message: "The recommend category statistic error."}
	ErrAddRecommendCategory     = &Errno{Code: 20101, Message: "The recommend category add error."}
	ErrUpdateRecommendCategory  = &Errno{Code: 20102, Message: "The recommend category update error."}
	ErrDeleteRecommendCategory  = &Errno{Code: 20102, Message: "The recommend category delete error."}
	ErrExistRecommendCategory   = &Errno{Code: 20103, Message: "The recommend category already exists."}

	// wallet supported chain errors
	ErrSupportedChainNotFound = &Errno{Code: 20101, Message: "The wallet supported chain was not found."}
	ErrCountSupportedChain    = &Errno{Code: 20102, Message: "The wallet supported chain statistic error."}
	ErrAddSupportedChain      = &Errno{Code: 20101, Message: "The wallet supported chain add error."}
	ErrDeleteSupportedChain   = &Errno{Code: 20102, Message: "The wallet supported chain delete error."}
	ErrExistSupportedChain    = &Errno{Code: 20103, Message: "The wallet supported chain already exists."}

	// user errors
	ErrUserTokenIncorrect = &Errno{Code: 40001, Message: "The user token was incorrect."}
	ErrUserAuthIncorrect  = &Errno{Code: 40001, Message: "The user auth was incorrect."}
	ErrUserNotFound       = &Errno{Code: 20101, Message: "The user was not found."}
	ErrPasswordIncorrect  = &Errno{Code: 20102, Message: "The password was incorrect."}
)
