package http

import (
	"context"
	"log"
	"net"
	"net/http"
	"net/netip"
	"os"
	"strings"
	"time"
)

type HttpServer struct {
	s    http.Server
	addr net.Addr
}

func NewHttpServer(r http.Handler) *HttpServer {
	return &HttpServer{s: http.Server{
		ReadTimeout:  3 * time.Second,
		WriteTimeout: 3 * time.Second,
		Handler:      r}}
}

func (s *HttpServer) Start(address string) error {
	var network string
	if !strings.ContainsRune(address, ':') {
		network = "unix"
	} else {
		ap, err := netip.ParseAddrPort(address)
		if err != nil {
			return err
		}

		if ap.Addr().Is4() {
			network = "tcp4"
		} else if ap.Addr().Is6() {
			network = "tcp6"
		}
	}

	listener, err := net.Listen(network, address)
	if err != nil {
		return err
	}

	if listener.Addr().Network() == "unix" {
		os.Chmod(address, 0777)
	}

	s.addr = listener.Addr()

	go func() {
		if err = s.s.Serve(listener); err != nil && err != http.ErrServerClosed {
			log.Fatalln(err)
		}
	}()

	return nil
}

func (s *HttpServer) Stop() error {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	if s.addr.Network() == "unix" {
		defer os.Remove(s.addr.String())
	}

	if err := s.s.Shutdown(ctx); err != nil {
		return err
	}

	return nil
}
