package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	sgrpc "go.unistack.org/micro-server-grpc/v4"
	"go.unistack.org/micro/v4"
	"go.unistack.org/micro/v4/server"
	grpc "google.golang.org/grpc"
	emptypb "google.golang.org/protobuf/types/known/emptypb"
)

func main() {
	switch os.Args[1] {
	case "server":
		TestServer()
	case "client":
		TestClient()
	}
}

type serv struct {
	UnimplementedTestServiceServer
}

func (s *serv) DoWork(ctx context.Context, in *emptypb.Empty) (*WorkResponse, error) {
	fmt.Println("Starting long-running operation")
	time.Sleep(4 * time.Second)
	select {
	case <-ctx.Done():
		fmt.Println("Operation interrupted")
		return nil, ctx.Err()
	default:
		fmt.Println("Operation completed")
		return &WorkResponse{Message: "Work done"}, nil
	}
}

func startServer(ctx context.Context) {
	s := sgrpc.NewServer(server.Name("Service"), server.Address("localhost:1234"))
	svc := micro.NewService(
		micro.Context(ctx),
		micro.Server(s),
	)
	svc.Init()
	RegisterTestServiceServer(s.GRPCServer(), &serv{})

	go func() {
		fmt.Printf("wait for ctx.Done\n")
		<-ctx.Done()
		fmt.Printf("wait for Stop\n")
		svc.Stop()
		fmt.Printf("Stopped\n")
	}()

	fmt.Printf("svc Run\n")
	svc.Run()
	fmt.Printf("svc End\n")
}

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

	log.Printf("create grpc conn\n")
	conn, _ := grpc.NewClient("localhost:1234", grpc.WithInsecure(), grpc.WithBlock())
	defer conn.Close()
	cli := NewTestServiceClient(conn)

	replyCh := make(chan string)
	go func() {
		resp, err := cli.DoWork(ctx, &emptypb.Empty{})
		if err != nil {
			fmt.Println("Client call failed:", err)
			replyCh <- ""
		} else {
			replyCh <- resp.Message
		}
	}()

	p, _ := os.FindProcess(os.Getpid())
	_ = p
	//_ = p.Signal(syscall.SIGTERM)

	select {
	case reply := <-replyCh:
		if reply != "Work done" {
			log.Printf("Expected reply 'Work done', got '%s'\n", reply)
		} else {
			log.Printf("all fine\n")
		}
	case <-ctx.Done():
		log.Printf("Request was not completed\n")
	}
}

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

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		sigReceived := <-sig
		fmt.Printf("handle signal %v, exiting\n", sigReceived)
		cancel()
	}()

	log.Printf("run server\n")
	startServer(ctx)
}
