package server

import (
	"context"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

type server struct {
	*http.Server
}

// New creates an HTTP server that listens on the given address and a channel that receives shutdown signals.
// The channel should be used to block a goroutine until it receives an OS signal, after which the server should be shutdown.
func New(addr string, handler http.Handler, log *log.Logger) (*server, chan os.Signal) {
	srv := &server{
		Server: &http.Server{
			Addr:        addr,
			Handler:     handler,
			ReadTimeout: 2 * time.Second,
			IdleTimeout: 65 * time.Second, // Set a value longer than the load balancer idle timeout.
			ErrorLog:    log,
		},
	}

	shutdown := make(chan os.Signal, 1)
	signal.Notify(shutdown, syscall.SIGINT, syscall.SIGTERM)

	return srv, shutdown
}

// Shutdown attempts to gracefully shutdown the server, waiting up to the specified
// timeout before forcefully closing all connections.
func (srv *server) Shutdown(timeout time.Duration) {
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	srv.SetKeepAlivesEnabled(false)
	if err := srv.Server.Shutdown(ctx); err != nil {
		if srv.ErrorLog != nil {
			srv.ErrorLog.Println("Unable to shutdown server:", err)
		} else {
			srv.ErrorLog.Println("Unable to shutdown server:", err)
		}
		_ = srv.Close()
	}
}
