package grpcutil

import (
	"context"
	"errors"
	"net"
	"time"

	"google.golang.org/grpc"
)

// ServeWithGracefulStop serves the gRPC listener until ctx.Done(), and then gracefully stops and waits for gracefulTimeout
// before definitively stopping.
func ServeWithGracefulStop(ctx context.Context, srv *grpc.Server, li net.Listener, gracefulTimeout time.Duration) error {
	go func() {
		// wait for the context to complete
		<-ctx.Done()

		sctx, stopped := context.WithCancel(context.Background())
		go func() {
			srv.GracefulStop()
			stopped()
		}()

		wait := time.NewTimer(gracefulTimeout)
		defer wait.Stop()

		select {
		case <-wait.C:
		case <-sctx.Done():
			return
		}

		// finally stop it completely
		srv.Stop()
	}()

	err := srv.Serve(li)
	if errors.Is(err, grpc.ErrServerStopped) {
		err = nil
	}
	return err
}