package service

import (
	"common/discover"
	"common/log"
	"common/utils"
	"context"
	"fmt"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/keepalive"
	"google.golang.org/grpc/status"
	"net"
	"sync"
	"time"
)

type IService interface {
	Init(addr string, port int32)
	Close()
}

type Base struct {
	Target  string
	SID     int64
	Serve   *grpc.Server
	EtcdTTL int64
	OnInit  func(serve *grpc.Server)
	OnClose func()

	wg *sync.WaitGroup
}

func (s *Base) Init(addr string, port int32) {
	s.wg = &sync.WaitGroup{}
	s.wg.Add(1)
	s.SID = utils.SnowflakeInstance().Generate().Int64()
	go func() {
		defer s.wg.Done()
		defer s.OnClose()
		defer discover.UnRegisterGrpcServer(s.SID)

		// 监听端口
		lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
		if err != nil {
			log.Errorf("%v ListenPort err: %v", s.Target, err)
			return
		}

		s.Serve = grpc.NewServer(
			grpc.UnaryInterceptor(
				func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
					defer func() {
						if r := recover(); r != nil {
							log.Errorf("server Panic: %v", r)
							err = status.Error(codes.Internal, fmt.Sprintf("%v", r))
						}
					}()
					resp, err = handler(ctx, req)
					return
				},
			),
			grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
				MinTime:             20 * time.Second,
				PermitWithoutStream: true,
			}),
		)
		s.OnInit(s.Serve)

		// 服务注册
		if err = discover.RegisterGrpcServer(s.Target, s.SID, fmt.Sprintf("%v:%d", addr, port), s.EtcdTTL); err != nil {
			log.Errorf("%v RegisterGrpcServer err: %v", s.Target, err)
			return
		}
		if err = s.Serve.Serve(lis); err != nil {
			log.Errorf("%v Serve err: %v", s.Target, err)
			return
		}
		log.Infof("%v server stop.", s.Target)
	}()
}

func (s *Base) Close() {
	if s.Serve != nil {
		s.Serve.Stop()
		s.wg.Wait()
	}
}
