package centralgw

import (
	"fmt"
	"net"
	"sync"

	"github.com/gin-gonic/gin"
	"google.golang.org/grpc"
)

func Run(getGRPCServer func() (server *grpc.Server, err error), getGateway func() (r *gin.Engine, err error), httpPort int, gRPCPort int) (err error) {
	exitCh := make(chan error)
	var once sync.Once
	wg := &WaitGroupWrapper{}

	exitFunc := func(err error) {
		once.Do(func() {
			if err != nil {
				exitCh <- err
			}
		})
	}

	wg.Wrap(func() {
		exitFunc(runGRPC(getGRPCServer, gRPCPort))
	})

	wg.Wrap(func() {
		exitFunc(runWeb(getGateway, httpPort))
	})

	return <-exitCh
}

type WaitGroupWrapper struct {
	sync.WaitGroup
}

func (w *WaitGroupWrapper) Wrap(cb func()) {
	w.Add(1)
	go func() {
		cb()
		w.Done()
	}()
}

func runWeb(getGateway func() (r *gin.Engine, err error), httpPort int) error {
	r, err := getGateway()
	if err != nil {
		return err
	}
	fmt.Println("[http] http api server launched, run:", httpPort)
	panic(fmt.Sprintf("grpc HTTP gateway died %+v", r.Run(fmt.Sprintf(":%d", httpPort))))
}

func runGRPC(getGRPCServer func() (server *grpc.Server, err error), gRPCPort int) error {
	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", gRPCPort))
	if err != nil {
		return err
	}

	s, err := getGRPCServer()
	if err != nil {
		return err
	}

	fmt.Println("[grpc] grpc server launched, run:", gRPCPort)
	return s.Serve(lis)
}
