package errs

import (
	"errors"
	"fmt"

	"github.com/tidbcloud/devops/api"
)

func APIErrorNew(code api.ErrCode, err error) APIError {
	return &apiErr{
		code: code,
		err:  err,
	}
}

func APIErrorf(code api.ErrCode, 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 &apiErr{
			code: aerr.ErrCode(), // inherit err code
			err:  err,
		}
	}

	if IsNotFoundInDB(err) {
		return &apiErr{
			code: api.ErrCodeNotFound,
			err:  err,
		}
	}

	return &apiErr{
		code: api.ErrCodeInternal,
		err:  err,
	}
}

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

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

type APIError interface {
	error
	ErrCode() api.ErrCode
	ErrMessage() string
}

type apiErr struct {
	code api.ErrCode
	err  error
}

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

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

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