package metricsserver

import (
	"context"
	"net/http"
	"strconv"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"golang.org/x/sync/errgroup"

	"go.ntppool.org/common/logger"
)

type Metrics struct {
	r *prometheus.Registry
}

func New() *Metrics {
	r := prometheus.NewRegistry()

	m := &Metrics{
		r: r,
	}

	return m
}

func (m *Metrics) Registry() *prometheus.Registry {
	return m.r
}

func (m *Metrics) Handler() http.Handler {

	log := logger.NewStdLog("prom http", false, nil)

	return promhttp.HandlerFor(m.r, promhttp.HandlerOpts{
		ErrorLog:          log,
		Registry:          m.r,
		EnableOpenMetrics: true,
	})
}

// ListenAndServe starts a goroutine with a server running on
// the specified port. The server will shutdown and return when
// the provided context is done
func (m *Metrics) ListenAndServe(ctx context.Context, port int) error {

	log := logger.Setup()

	srv := &http.Server{
		Addr:         ":" + strconv.Itoa(port),
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 20 * time.Second,
		IdleTimeout:  120 * time.Second,
		Handler:      m.Handler(),
	}

	g, ctx := errgroup.WithContext(ctx)

	g.Go(func() error {
		err := srv.ListenAndServe()
		if err != nil && err != http.ErrServerClosed {
			log.Warn("metrics server done listening", "err", err)
			return err
		}
		return nil
	})

	<-ctx.Done()

	if err := srv.Shutdown(ctx); err != nil {
		log.Error("metrics server shutdown failed", "err", err)
		return err
	}

	return g.Wait()
}