package twitch

import (
	"fmt"
)

// HTTPError represents an HTTP error containing the response body (or
// the wrapped error occurred while readiny the body) and the status
// code returned by the server
type HTTPError struct {
	Body []byte
	Code int
	Err  error
}

// ErrAnyHTTPError can be used in errors.Is() to match an HTTPError
// with any status code
var ErrAnyHTTPError = newHTTPError(0, nil, nil)

func newHTTPError(status int, body []byte, wrappedErr error) HTTPError {
	return HTTPError{
		Body: body,
		Code: status,
		Err:  wrappedErr,
	}
}

// Error implements the error interface and returns a formatted version
// of the error including the body, might therefore leak confidential
// information when included in the response body
func (h HTTPError) Error() string {
	selfE := fmt.Sprintf("unexpected status %d", h.Code)
	if h.Body != nil {
		selfE = fmt.Sprintf("%s (%s)", selfE, h.Body)
	}

	if h.Err == nil {
		return selfE
	}

	return fmt.Sprintf("%s: %s", selfE, h.Err)
}

// Is checks whether the given error is an HTTPError and the status
// code matches the given error
func (h HTTPError) Is(target error) bool {
	ht, ok := target.(HTTPError)
	if !ok {
		return false
	}

	return ht.Code == 0 || ht.Code == h.Code
}

// Unwrap returns the wrapped error occurred when reading the body
func (h HTTPError) Unwrap() error {
	return h.Err
}