package rest

import (
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"runtime"
	"strings"

	"github.com/go-pkgz/rest/logger"
)

// ErrorLogger wraps logger.Backend
type ErrorLogger struct {
	l logger.Backend
}

// NewErrorLogger creates ErrorLogger for given Backend
func NewErrorLogger(l logger.Backend) *ErrorLogger {
	return &ErrorLogger{l: l}
}

// Log sends json error message {error: msg} with error code and logging error and caller
func (e *ErrorLogger) Log(w http.ResponseWriter, r *http.Request, httpCode int, err error, msg ...string) {
	m := ""
	if len(msg) > 0 {
		m = strings.Join(msg, ". ")
	}
	if e.l != nil {
		e.l.Logf("%s", errDetailsMsg(r, httpCode, err, m))
	}
	renderJSONWithStatus(w, JSON{"error": m}, httpCode)
}

// SendErrorJSON sends {error: msg} with error code and logging error and caller
func SendErrorJSON(w http.ResponseWriter, r *http.Request, l logger.Backend, code int, err error, msg string) {
	if l != nil {
		l.Logf("%s", errDetailsMsg(r, code, err, msg))
	}
	renderJSONWithStatus(w, JSON{"error": msg}, code)
}

func errDetailsMsg(r *http.Request, code int, err error, msg string) string {

	q := r.URL.String()
	if qun, e := url.QueryUnescape(q); e == nil {
		q = qun
	}

	srcFileInfo := ""
	if pc, file, line, ok := runtime.Caller(2); ok {
		fnameElems := strings.Split(file, "/")
		funcNameElems := strings.Split(runtime.FuncForPC(pc).Name(), "/")
		srcFileInfo = fmt.Sprintf(" [caused by %s:%d %s]", strings.Join(fnameElems[len(fnameElems)-3:], "/"),
			line, funcNameElems[len(funcNameElems)-1])
	}

	remoteIP := r.RemoteAddr
	if pos := strings.Index(remoteIP, ":"); pos >= 0 {
		remoteIP = remoteIP[:pos]
	}
	if err == nil {
		err = errors.New("no error")
	}
	return fmt.Sprintf("%s - %v - %d - %s - %s%s", msg, err, code, remoteIP, q, srcFileInfo)
}
