package errs

import (
	"errors"
	"fmt"
	"net/http"
)

// APIErrorf create an APIError from err
func APIErrorNew(code int, err error) APIError {
	return &apiErr{
		code: code,
		err:  err,
	}
}

// APIErrorf create an APIError from format
func APIErrorf(code int, format string, args ...any) APIError {
	return &apiErr{
		code: code,
		err:  fmt.Errorf(format, args...),
	}
}

// APIErrorWrap wrap an error to an APIError
func APIErrorWrap(err error) APIError {
	if err == nil {
		return nil
	}

	if aerr, is := AsAPIError(err); is {
		return aerr
	}

	if IsNotFoundInDB(err) {
		return &apiErr{
			code: http.StatusNotFound,
			err:  err,
		}
	}

	return &apiErr{
		code: http.StatusInternalServerError,
		err:  err,
	}
}

func AsAPIError(err error) (APIError, bool) {
	if err == nil {
		return nil, false
	}

	var apiErr APIError
	is := errors.As(err, &apiErr)
	return apiErr, is
}

type APIError interface {
	error
	ErrCode() int
	ErrMessage() string
}

type apiErr struct {
	code int
	err  error
}

func (e *apiErr) Error() string {
	return fmt.Sprintf("code:%d msg:%s", e.code, e.err)
}

func (e *apiErr) ErrCode() int {
	return e.code
}

func (e *apiErr) ErrMessage() string {
	return e.err.Error()
}
