package grpc

import (
	"context"
	"fmt"
	"github.com/UpmeshLTD/urus-aio/infrastructure/patterns"
	"github.com/UpmeshLTD/urus-aio/infrastructure/server"
	"net"

	"google.golang.org/grpc"
)

type RegisterFunc func(svr *grpc.Server) error

// Transport represents a gRPC transport.
type Transport interface {
	server.Transport
}

// grpcTransport implements Transport interface.
type grpcTransport struct {
	patterns.Runnable
	c            *Config
	registerFunc RegisterFunc
	svr          *grpc.Server
}

// NewTransport returns a new gRPC Transport with given Config and RegisterFunc.
func NewTransport(c *Config, registerFunc RegisterFunc) Transport {
	return &grpcTransport{
		Runnable:     patterns.NewRunnable(),
		c:            c,
		registerFunc: registerFunc,
	}
}

func (t *grpcTransport) StartWithContext(ctx context.Context) (err error) {
	if err := t.Runnable.StartWithContext(ctx); err != nil {
		return err
	}

	listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", t.c.Host, t.c.Port))
	if err != nil {
		return err
	}

	t.svr = grpc.NewServer()
	if err := t.registerFunc(t.svr); err != nil {
		return err
	}

	return t.svr.Serve(listener)
}

func (t *grpcTransport) Stop() error {
	if err := t.Runnable.Stop(); err != nil {
		return err
	}

	t.svr.Stop()
	return nil
}
