package handler

import (
	"context"
	"net/http"
	"time"

	"github.com/AlchemyTelcoSolutions/xutils-go/xlogger"
	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"
	"go.uber.org/zap"
)

var clientAddressKey = "clientAddress"
var clientHostKey = "clientHost"
var clientIdKey = "clientId"
var usernameKey = "usernameKey"

// loggerKey is to be used with Context.Value() to retrieve the request logger
var loggerKey string = "loggerKey"

func SetRequestLogger(logger xlogger.Logger) func(next http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			l := logger.With(
				zap.Any("request_id", r.Context().Value(middleware.RequestIDKey)),
				zap.String("kong_request_id", r.Header.Get("Kong-Request-ID")),
				zap.String("remote_ip", r.RemoteAddr),
				zap.String("url", r.URL.Path),
				zap.String("path", chi.RouteContext(r.Context()).RoutePattern()),
				zap.String("proto", r.Proto),
				zap.String("method", r.Method),
				zap.String("user_agent", r.Header.Get("User-Agent")),
				zap.String("query", r.URL.RawQuery),
				zap.Any("username", r.Context().Value(usernameKey)),
				zap.Any("client_id", r.Context().Value(clientIdKey)),
				zap.Any("client_address", r.Context().Value(clientAddressKey)),
				zap.Any("client_host", r.Context().Value(clientHostKey)),
			)
			ctx := context.WithValue(r.Context(), loggerKey, l)
			next.ServeHTTP(w, r.WithContext(ctx))
		}
		return http.HandlerFunc(fn)
	}
}

func SetResponseLogger(logger xlogger.Logger) func(next http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
			t1 := time.Now()

			defer func() {
				t2 := time.Now()
				// log end request
				logger.Info(r.Method+" "+r.URL.Path,
					zap.String("remote_ip", r.RemoteAddr),
					zap.String("method", r.Method),
					zap.String("url", r.URL.Path),
					zap.String("path", chi.RouteContext(r.Context()).RoutePattern()),
					zap.String("query", r.URL.RawQuery),
					zap.String("proto", r.Proto),
					zap.String("user_agent", r.Header.Get("User-Agent")),
					zap.Any("status", ww.Status()),
					zap.Float64("latency_ms", float64(t2.Sub(t1).Nanoseconds())/1000000.0),
					zap.String("bytes_in", r.Header.Get("Content-Length")),
					zap.Int("bytes_out", ww.BytesWritten()),
					zap.Any("request_id", r.Context().Value(middleware.RequestIDKey)),
					zap.String("kong_request_id", r.Header.Get("Kong-Request-ID")),
					zap.Any("username", r.Context().Value(usernameKey)),
					zap.Any("client_id", r.Context().Value(clientIdKey)),
					zap.Any("client_address", r.Context().Value(clientAddressKey)),
					zap.Any("client_host", r.Context().Value(clientHostKey)),
				)
			}()

			next.ServeHTTP(ww, r)
		}
		return http.HandlerFunc(fn)
	}
}
