package routebuildermdl

import (
	"context"
	"encoding/json"
	"net"

	"google.golang.org/grpc"

	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/authmdl/jwtmdl"
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/authmdl/roleenforcemdl"
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/errormdl"
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/grpcbuildermdl"
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/loggermdl"
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/servicebuildermdl"
)

// Server server
type Server struct{}

// GRPCInit init
func GRPCInit(GRPCPort net.Listener /* , serverStatus chan string */) {
	loggermdl.LogInfo("GRPC init called")
	s := grpc.NewServer()
	grpcbuildermdl.RegisterGRPCCheckServer(s, &Server{})
	grpcbuildermdl.RegisterGRPCServiceServer(s, &Server{})
	if err := s.Serve(GRPCPort); err != nil {
		loggermdl.LogError("Unable to start GRPC server: %v", err)
	}
}

//Employee ... Employee
type Employee struct {
	Name   string `json:"empname"`
	Number int    `json:"empid"`
}

// GRPCHandler GRPCHandler
func (*Server) GRPCHandler(ctx context.Context, req *grpcbuildermdl.GRPCRequest) (*grpcbuildermdl.GRPCByteResponse, error) {
	loggermdl.LogError("GRPC Handler inoked: ", req)
	principal := servicebuildermdl.Principal{}
	if req.GetGrpcMessage().GetIsRestricted() {
		claim, _ := jwtmdl.GeneratePricipleObjUsingToken(req.GetGrpcMessage().GetToken(), jwtmdl.GlobalJWTKey)
		groups, grperr := roleenforcemdl.GetGroupNames(claim, "groups")
		if errormdl.CheckErr(grperr) != nil {
			loggermdl.LogError(grperr)
			return nil, errormdl.CheckErr(grperr)
		}
		userID, ok := claim["userId"].(string)
		if !ok || len(userID) < 2 {
			loggermdl.LogError("Unable to parse UserID from JWT Token")
			return nil, errormdl.Wrap("Unable to parse UserID from JWT Token")
		}
		rawMetadata, ok := claim["metadata"]
		if ok {
			loggermdl.LogError(rawMetadata)
			metadata, ok := rawMetadata.(string)
			if !ok {
				loggermdl.LogError("Unable to parse metadata from JWT Token")
				return nil, errormdl.Wrap("Unable to parse metadata from JWT Token")
			}
			principal.Metadata = metadata
		}
		principal.Groups = groups
		principal.UserID = userID
		principal.Token = req.GetGrpcMessage().GetToken()
	}

	loggermdl.LogError("<Request Message>", req)
	result, nextDynamicPage, ab, isCompressed, errorCode, err := executeService(
		req.GetGrpcMessage().GetName(),
		req.GetGrpcMessage().GetData(), req.GetGrpcMessage().GetIsRestricted(),
		req.GetGrpcMessage().GetIsRoleBased(), false, principal)
	e, _ := json.Marshal(result)
	res := &grpcbuildermdl.GRPCByteResponse{
		Data: e,
	}
	loggermdl.LogError(result, string(e), nextDynamicPage, ab, isCompressed, errorCode, err)
	return res, err
}

// GRPCCheck GRPCCheck
func (*Server) GRPCCheck(ctx context.Context, req *grpcbuildermdl.GRPCRequest) (*grpcbuildermdl.GRPCResponse, error) {
	loggermdl.LogError("GRPC Check Invoked: ", req)
	claim, _ := jwtmdl.GeneratePricipleObjUsingToken(req.GetGrpcMessage().GetToken(), jwtmdl.GlobalJWTKey)
	principal := servicebuildermdl.Principal{}
	groups, grperr := roleenforcemdl.GetGroupNames(claim, "groups")
	if errormdl.CheckErr(grperr) != nil {
		loggermdl.LogError(grperr)
		return nil, errormdl.CheckErr(grperr)
	}
	userID, ok := claim["userId"].(string)
	if !ok || len(userID) < 2 {
		loggermdl.LogError("Unable to parse UserID from JWT Token")
		return nil, errormdl.Wrap("Unable to parse UserID from JWT Token")
	}
	rawMetadata, ok := claim["metadata"]
	if ok {
		loggermdl.LogError(rawMetadata)
		metadata, ok := rawMetadata.(string)
		if !ok {
			loggermdl.LogError("Unable to parse metadata from JWT Token")
			return nil, errormdl.Wrap("Unable to parse metadata from JWT Token")
		}
		principal.Metadata = metadata
	}
	principal.Groups = groups
	principal.UserID = userID
	principal.Token = req.GetGrpcMessage().GetToken()
	result, nextDynamicPage, ab, isCompressed, errorCode, err := executeService(
		req.GetGrpcMessage().GetName(),
		req.GetGrpcMessage().GetData(),
		req.GetGrpcMessage().GetIsRestricted(),
		req.GetGrpcMessage().GetIsRoleBased(), false, principal)
	res := &grpcbuildermdl.GRPCResponse{
		Data: "Response from GRPC Check service",
	}
	loggermdl.LogError(result, nextDynamicPage, ab, isCompressed, errorCode, err)
	return res, err
}