package server

import (
	"context"
	"errors"
	"fmt"
	"net/http"
	"sync"
	"time"

	"github.com/pingcap/log"
	rm "github.com/tidbcloud/aws-shared-provider/pkg/tidbworker/resourcemanager/types"
	"go.uber.org/zap"
)

const shutdownTimeout = 3 * time.Second

type Server struct {
	sync.Mutex
	ctx context.Context

	manager rm.PoolManager
	addr    string
	server  *http.Server
	mux     *http.ServeMux
}

func NewServer(manager rm.PoolManager, addr string) *Server {
	server := &Server{
		manager: manager,
		addr:    addr,
		mux:     http.NewServeMux(),
	}
	// Register server methods.
	server.registerDebug()
	return server
}

func (s *Server) Start(ctx context.Context) error {
	s.Lock()
	defer s.Unlock()
	s.ctx = ctx
	s.server = &http.Server{
		Addr:    s.addr,
		Handler: s.mux,
	}
	go func() {
		if err := s.server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			log.Error("failed to start http server", zap.Error(err))
		}
	}()
	log.Info("http server started", zap.String("addr", s.addr))
	return nil
}

func (s *Server) Stop() error {
	s.Lock()
	defer s.Unlock()

	if s.server == nil {
		return fmt.Errorf("server is not running")
	}
	ctx, cancel := context.WithTimeout(s.ctx, shutdownTimeout)
	defer cancel()
	if err := s.server.Shutdown(ctx); err != nil {
		return err
	}
	log.Info("http server stopped", zap.String("addr", s.addr))
	return nil
}
