package metrics

import (
	"time"

	"github.com/pkg/errors"
	"github.com/prometheus/client_golang/prometheus"

	"github.com/ThreeDotsLabs/watermill/message"
)

var (
	handlerLabelKeys = []string{
		LabelKeyEventType,
		LabelKeySource,
		LabelKeyGroup,
		LabelKeyRetryTimes,
		LabelKeySuccess,
	}
)

// HandlerPrometheusMetricsMiddleware is a middleware that captures Prometheus metrics.
type HandlerPrometheusMetricsMiddleware struct {
	handlerExecutionTimeSeconds *prometheus.HistogramVec
}

// Middleware returns the middleware ready to be used with watermill's Router.
func (m HandlerPrometheusMetricsMiddleware) Middleware(h message.HandlerFunc) message.HandlerFunc {
	return func(msg *message.Message) (messages []*message.Message, err error) {
		start := time.Now()

		defer func() {
			labels := labelsFromCtx(msg.Context(), handlerLabelKeys...)
			m.handlerExecutionTimeSeconds.With(labels).Observe(time.Since(start).Seconds())
		}()

		return h(msg)
	}
}

// NewRouterMiddleware returns new middleware.
func (b PrometheusMetricsBuilder) NewRouterMiddleware() HandlerPrometheusMetricsMiddleware {
	var err error
	m := HandlerPrometheusMetricsMiddleware{}

	m.handlerExecutionTimeSeconds, err = b.registerHistogramVec(prometheus.NewHistogramVec(
		prometheus.HistogramOpts{
			Namespace: b.Namespace,
			Subsystem: b.Subsystem,
			Name:      "execution_time_seconds",
			Help:      "The total time elapsed while executing the handler function in seconds",
			Buckets:   executionTimeBuckets,
		},
		handlerLabelKeys,
	))
	if err != nil {
		panic(errors.Wrap(err, "could not register handler execution time metric"))
	}

	return m
}
