package twitchclient

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)

// Error returned by twitchclients.
// Service 4xx and 5xx responses are expected to be JSON, if they are not JSON
// then the message contains all the response as plain text.
type Error struct {
	Message   string `json:"message"`
	ErrorCode string `json:"error_code"` // optional string used by some services with more error types

	StatusCode int `json:"-"` // convenience with the same response status
}

// Error implements the error interface
func (e *Error) Error() string {
	if e == nil {
		return "<nil>"
	}
	return strconv.Itoa(e.StatusCode) + ": " + e.Message
}

// StatusCode returns the HTTP status code from a *twitchclient.Error,
// or 0 if the error is of a different type.
func StatusCode(err error) int {
	if tcErr, ok := err.(*Error); ok {
		return tcErr.StatusCode
	}
	return 0 // unknown
}

// ErrorFromFailedResponse decodes a response body from a failed HTTP response into a *twitchclient.Error.
// The response should be JSON with "message" and (optional) "error_code" fields, otherwise the message
// will be the full body as String.
// The caller must close the response body after reading it with this method.
func ErrorFromFailedResponse(resp *http.Response) *Error {
	if resp == nil {
		return &Error{Message: "twitchclient: unexpected nil *http.Response when handling error"}
	}

	twitchError := &Error{}
	contentType := resp.Header.Get("Content-Type")
	if strings.HasPrefix(contentType, "application/json") {
		err := json.NewDecoder(resp.Body).Decode(twitchError)
		if err != nil {
			twitchError.Message = "Unable to decode JSON response: " + err.Error()
		}

	} else { // if not "application/json", then assume text/plain
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			twitchError.Message = "Unable to read response body: " + err.Error()
		} else {
			twitchError.Message = string(body)
		}
	}
	twitchError.StatusCode = resp.StatusCode
	return twitchError
}

// HandleFailedResponse is an alias for backwards compatibility
var HandleFailedResponse = ErrorFromFailedResponse
