package graceful

import (
	"context"
	"golang.org/x/sync/errgroup"
	"log"
	"os"
	"os/signal"
	"syscall"
)

func init() {
	log.SetOutput(os.Stdout)
}

type IRunner interface {
	Run(ctx context.Context) error
	Stop()
}

type Graceful struct{}

type Opt func(*Graceful)

func New() *Graceful {
	return &Graceful{}
}

func (g *Graceful) Run(r ...IRunner) {
	eg := &errgroup.Group{}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	for _, v := range r {
		goRun(ctx, eg, v)
	}

	eg.Go(func() error {
		ch := make(chan os.Signal, 1)
		signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)

		select {
		case v := <-ch:
			log.Printf("catch notfiy stop: %v", v)
		}

		cancel()

		for _, v := range r {
			v.Stop()
		}

		return nil
	})

	defer func() {
		log.Printf("server stop")
	}()

	err := eg.Wait()
	if err != nil {
		log.Println(err)
		return
	}

}

func goRun(ctx context.Context, eg *errgroup.Group, r IRunner) {
	eg.Go(func() error {
		err := r.Run(ctx)
		if err != nil {
			log.Printf("run err: %s", err)
			return err
		}

		return nil
	})
}
