package main

import (
	"context"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"

	"github.com/gorilla/handlers"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

// HTTPOutput serves the Prometheus metrics endpoint.
type HTTPOutput struct {
	server *http.Server
	config *HTTPOutputConfig
}

// NewHTTPOutput creates the HTTP output and applies the current configuration.
func NewHTTPOutput() *HTTPOutput {
	s := new(HTTPOutput)
	s.server = &http.Server{}
	s.Reload()
	return s
}

// AddHandlers (re)builds the request multiplexer: the metrics endpoint plus a
// landing page linking to it.
func (s *HTTPOutput) AddHandlers() {
	mux := http.NewServeMux()
	s.server.Handler = mux

	mux.Handle(s.config.MetricsPath, handlers.CombinedLoggingHandler(os.Stdout, promhttp.HandlerFor(app.registry, promhttp.HandlerOpts{})))
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(`<html>
             <head><title>Drive Health Metrics</title></head>
             <body>
             <h1>Drive Health Metrics</h1>
             <p><a href='` + s.config.MetricsPath + `'>Metrics</a></p>
             </body>
             </html>`))
	})
}

// Reload refreshes the configuration, listen address, and handlers.
func (s *HTTPOutput) Reload() {
	s.config = &app.config.HTTP
	s.server.Addr = fmt.Sprintf("%s:%d", s.config.BindAddr, s.config.Port)
	s.AddHandlers()
}

// OutputEnabled reports whether the HTTP output is enabled.
func (s *HTTPOutput) OutputEnabled() bool {
	return s.config.Enabled
}

// Start launches the server and blocks until it is accepting connections.
func (s *HTTPOutput) Start(ctx context.Context) {
	isListening := make(chan bool)
	go s.StartWithIsListening(ctx, isListening)
	<-isListening
}

// StartWithIsListening runs the server, signalling on isListening once the
// listener is bound, and shutting down when the context is cancelled.
func (s *HTTPOutput) StartWithIsListening(ctx context.Context, isListening chan bool) {
	if !s.config.Enabled {
		isListening <- true
		return
	}

	go func() {
		<-ctx.Done()
		if err := s.server.Shutdown(context.Background()); err != nil {
			log.Println("Error shutting down http server:", err)
		}
	}()

	log.Println("Starting http server:", s.server.Addr)
	l, err := net.Listen("tcp", s.server.Addr)
	if err != nil {
		log.Fatal("Listen: ", err)
	}
	isListening <- true
	if err := s.server.Serve(l); err != nil && err != http.ErrServerClosed {
		log.Println("HTTP server failure:", err)
	}
}
