package middleware

import (
	"context"
	"github.com/UpmeshLTD/urus-aio/infrastructure/logging"
	"github.com/UpmeshLTD/urus-aio/infrastructure/server/endpoint"
	"time"

	"go.opencensus.io/trace"
)

// LoggerInjection is a middleware that injects a logger to incoming context and passes it on to the downstream
// endpoint.
func LoggerInjection(logger logging.Logger) endpoint.Middleware {
	return func(next endpoint.Endpoint) endpoint.Endpoint {
		return endpoint.EndpointFunc(func(ctx context.Context, request interface{}) (response interface{}, err error) {
			cctx := logging.NewContext(ctx, logger)
			return next.Invoke(cctx, request)
		})
	}
}

// RequestLogging is a middleware that logs whenever and endpoint is called.
//
// The difference between this and transport-layer request logging is that it simplifies the extraction of the request
// and response, rather than requiring complex data buffering such as copying body buffer out from the request.
func RequestLogging() endpoint.Middleware {
	return func(next endpoint.Endpoint) endpoint.Endpoint {
		return endpoint.EndpointFunc(func(ctx context.Context, request interface{}) (response interface{}, err error) {
			now := time.Now()
			logger := logging.FromContext(ctx)

			response, err = next.Invoke(ctx, request)

			elapsedMs := time.Since(now).Milliseconds()
			metadata := next.Metadata()

			span := trace.FromContext(ctx)
			spanCtx := span.SpanContext()

			logger.Infow("endpoint request",
				"endpoint", metadata.Name,
				"span_id", spanCtx.SpanID.String(),
				"trace_id", spanCtx.TraceID.String(),
				"timestamp", now,
				"latency_ms", elapsedMs,
				"request", request,
				"response", response,
				"error", err,
			)

			return response, err
		})
	}
}
