package error

import (
	"net/http"
	"strings"

	"github.com/joomcode/errorx"
)

var (
	ErrUnauthorized       = errorx.CommonErrors.NewType("unauthorized")
	ErrForbidden          = errorx.CommonErrors.NewType("forbidden")
	ErrBadRequest         = errorx.CommonErrors.NewType("bad_request")
	ErrNotFound           = errorx.CommonErrors.NewType("not_found")
	ErrPreConditionFailed = errorx.CommonErrors.NewType("precondition_failed")
	ErrTooManyRequest     = errorx.CommonErrors.NewType("Too many requests, please retry later.")
	ErrInternal           = errorx.CommonErrors.NewType("internal")

	propHTTPCode = errorx.RegisterProperty("http_code")
)

func buildSimpleMessage(err error) string {
	if err == nil {
		return ""
	}

	mb := strings.Builder{}
	isFirstMsg := true
	cause := err
	for cause != nil {
		causeEx := errorx.Cast(cause)
		var msg string
		if causeEx == nil {
			msg = cause.Error()
		} else {
			msg = causeEx.Message()
		}

		if len(msg) > 0 {
			if !isFirstMsg {
				mb.WriteString(", caused by: ")
			}
			mb.WriteString(msg)
			isFirstMsg = false
		}

		if causeEx == nil {
			// This is already an error interface. It is not possible to get cause any more.
			break
		}
		cause = causeEx.Cause()
	}

	if isFirstMsg {
		// No message is successfully extracted
		return err.Error()
	}
	return mb.String()
}

func buildCode(err error) string {
	if err == nil {
		return ""
	}

	cause := err
	for cause != nil {
		causeEx := errorx.Cast(cause)
		if causeEx == nil {
			break
		}
		if causeEx.Type().RootNamespace().FullName() == "synthetic" {
			// Ignore standard transparent types..
			// User-defined transparent types are not detectable however.
			cause = causeEx.Cause()
		} else {
			return causeEx.Type().FullName()
		}
	}
	return ErrInternal.FullName()
}

func extractHTTPCodeFromError(err error) int {
	if err == nil {
		return http.StatusOK
	}

	ex := errorx.Cast(err)
	if ex == nil {
		return http.StatusInternalServerError
	}

	v, ok := ex.Property(propHTTPCode)
	if ok {
		return v.(int)
	}

	if ex.IsOfType(ErrUnauthorized) {
		return http.StatusUnauthorized
	}
	if ex.IsOfType(ErrForbidden) {
		return http.StatusForbidden
	}
	if ex.IsOfType(ErrBadRequest) {
		return http.StatusBadRequest
	}
	if ex.IsOfType(ErrNotFound) {
		return http.StatusNotFound
	}
	if ex.IsOfType(ErrInternal) {
		return http.StatusInternalServerError
	}
	if ex.IsOfType(ErrPreConditionFailed) {
		return http.StatusPreconditionFailed
	}

	if ex.IsOfType(ErrTooManyRequest) {
		return http.StatusTooManyRequests
	}

	return http.StatusInternalServerError
}
