package middlewares

import (
	"net"
	"net/http"
	"time"

	"go.uber.org/zap"
)

type loggedResponseWriter struct {
	w             http.ResponseWriter
	statusCode    int
	contentLength int
}

func (lr *loggedResponseWriter) Header() http.Header {
	return lr.w.Header()
}

func (lr *loggedResponseWriter) Write(dat []byte) (int, error) {
	if lr.statusCode < 100 {
		lr.statusCode = http.StatusOK
	}
	res, err := lr.w.Write(dat)
	lr.contentLength += res
	return res, err
}

func (lr *loggedResponseWriter) WriteHeader(statusCode int) {
	lr.statusCode = statusCode
	lr.w.WriteHeader(statusCode)
}

type LoggerMiddleware struct {
	l *zap.SugaredLogger
	h http.Handler
}

func (lm *LoggerMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	recorder := loggedResponseWriter{
		contentLength: 0,
		statusCode:    -1,
		w:             w,
	}
	lm.h.ServeHTTP(&recorder, r)

	method := r.Method
	route := r.RequestURI
	currentTime := time.Now().UTC()
	httpVersion := r.Proto

	clientIP, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		lm.l.Errorf("Failed to read remote IP: %s", err.Error())
		clientIP = "unknown"
	}

	lm.l.Infof(`%s - [%s] "%s %s %s" %d %d`, clientIP, currentTime.Format(time.RFC3339), method, route, httpVersion, recorder.statusCode, recorder.contentLength)
}
