package sdk

import (
	"context"
	"fmt"
	"net"

	pb "github.com/dsrvlabs/vatz-proto/plugin/v1"
	"github.com/rs/zerolog/log"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
	"google.golang.org/protobuf/types/known/emptypb"
	structpb "google.golang.org/protobuf/types/known/structpb"
)

type grpcServer struct {
	pb.UnimplementedPluginServer

	srv       *grpc.Server
	callbacks []func(map[string]*structpb.Value, map[string]*structpb.Value) (CallResponse, error)
}

// Verify returns liveness.
func (s *grpcServer) Verify(context.Context, *emptypb.Empty) (*pb.VerifyInfo, error) {
	return &pb.VerifyInfo{
		VerifyMsg: "OK",
	}, nil
}

// Execute runs plugin features.
func (s *grpcServer) Execute(ctx context.Context, req *pb.ExecuteRequest) (*pb.ExecuteResponse, error) {
	log.Info().Str("module", "grpc").Msg("Execute")

	resp := &pb.ExecuteResponse{
		ResourceType: PluginName,
	}

	for _, f := range s.callbacks {
		var (
			executeInfo map[string]*structpb.Value
			option      map[string]*structpb.Value
		)

		if req.GetExecuteInfo() != nil {
			executeInfo = req.GetExecuteInfo().GetFields()
		}

		if req.GetOptions() != nil {
			option = req.GetOptions().GetFields()
		}

		callResp, err := f(executeInfo, option)

		if err != nil {
			resp.Severity = pb.SEVERITY_ERROR
			resp.State = pb.STATE_FAILURE
			resp.Message = err.Error()
		} else {
			resp.Severity = callResp.Severity
			resp.State = callResp.State
			resp.Message = callResp.Message
		}
	}

	return resp, nil
}

// Start starts gRPC service.
func (s *grpcServer) Start(ctx context.Context, address string, port int) error {
	log.Info().Str("module", "grpc").Msg("Start")

	c, err := net.Listen("tcp", fmt.Sprintf("%s:%d", address, port))
	if err != nil {
		log.Error().Str("module", "grpc").Msg(err.Error())
		return err
	}

	s.srv = grpc.NewServer()

	pb.RegisterPluginServer(s.srv, s)
	reflection.Register(s.srv)

	return s.srv.Serve(c)
}

func (s *grpcServer) Stop() {
	log.Info().Str("module", "grpc").Msg("Stop")

	if s.srv != nil {
		s.srv.GracefulStop()
	}
}
