/*
* Copyright 2018-2024 Open Networking Foundation (ONF) and the ONF Contributors

* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at

* http://www.apache.org/licenses/LICENSE-2.0

* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
 */
package grpc

import (
	"context"
	"net"

	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
	grpc_opentracing "github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing"
	"github.com/opencord/voltha-lib-go/v7/pkg/log"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/reflection"
	"google.golang.org/grpc/status"
)

/*
To add a GRPC server to your existing component simply follow these steps:

1. Create a server instance by passing the host and port where it should run and optionally add certificate information

	e.g.
	s.server = server.NewGrpcServer(s.config.GrpcHost, s.config.GrpcPort, nil, false)

2. Create a function that will register your service with the GRPC server

    e.g.
	f := func(gs *grpc.Server) {
		voltha.RegisterVolthaReadOnlyServiceServer(
			gs,
			core.NewReadOnlyServiceHandler(s.root),
		)
	}

3. Add the service to the server

    e.g.
	s.server.AddService(f)

4. Start the server

	s.server.Start(ctx)
*/

// Interface allows probes to be attached to server
// A probe must support the IsReady() method
type ReadyProbe interface {
	IsReady() bool
}

type GrpcServer struct {
	gs       *grpc.Server
	address  string
	secure   bool
	services []func(*grpc.Server)
	probe    ReadyProbe // optional

	*GrpcSecurity
}

/*
Instantiate a GRPC server data structure
*/
func NewGrpcServer(
	address string,
	certs *GrpcSecurity,
	secure bool,
	probe ReadyProbe,
) *GrpcServer {
	server := &GrpcServer{
		address:      address,
		secure:       secure,
		GrpcSecurity: certs,
		probe:        probe,
	}
	return server
}

/*
Start prepares the GRPC server and starts servicing requests
*/
func (s *GrpcServer) Start(ctx context.Context, opts ...grpc.ServerOption) {

	lis, err := net.Listen("tcp", s.address)
	if err != nil {
		logger.Fatalf(ctx, "failed to listen: %v", err)
	}

	// Use Intercepters to automatically inject and publish Open Tracing Spans by this GRPC server
	serverOptions := []grpc.ServerOption{
		grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
			grpc_opentracing.StreamServerInterceptor(grpc_opentracing.WithTracer(log.ActiveTracerProxy{})),
		)),
		grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
			grpc_opentracing.UnaryServerInterceptor(grpc_opentracing.WithTracer(log.ActiveTracerProxy{})),
			mkServerInterceptor(s),
		))}

	if s.secure && s.GrpcSecurity != nil {
		creds, err := credentials.NewServerTLSFromFile(s.CertFile, s.KeyFile)
		if err != nil {
			logger.Fatalf(ctx, "could not load TLS keys: %s", err)
		}

		serverOptions = append(serverOptions, grpc.Creds(creds))
		s.gs = grpc.NewServer(append(serverOptions, opts...)...)
	} else {
		logger.Info(ctx, "starting-insecure-grpc-server")
		s.gs = grpc.NewServer(append(serverOptions, opts...)...)
	}

	// Register all required services
	for _, service := range s.services {
		service(s.gs)
	}
	reflection.Register(s.gs)

	if err := s.gs.Serve(lis); err != nil {
		logger.Fatalf(ctx, "failed to serve: %v\n", err)
	}
}

// Make a serverInterceptor for the given GrpcServer
// This interceptor will check whether there is an attached probe,
// and if that probe indicates NotReady, then an UNAVAILABLE
// response will be returned.
func mkServerInterceptor(s *GrpcServer) func(ctx context.Context,
	req interface{},
	info *grpc.UnaryServerInfo,
	handler grpc.UnaryHandler) (interface{}, error) {

	return func(ctx context.Context,
		req interface{},
		info *grpc.UnaryServerInfo,
		handler grpc.UnaryHandler) (interface{}, error) {

		if (s.probe != nil) && (!s.probe.IsReady()) {
			logger.Warnf(ctx, "Grpc request received while not ready %v", req)
			return nil, status.Error(codes.Unavailable, "system is not ready")
		}

		// Calls the handler
		h, err := handler(ctx, req)

		return h, err
	}
}

/*
Stop servicing GRPC requests
*/
func (s *GrpcServer) Stop() {
	if s.gs != nil {
		s.gs.Stop()
	}
}

/*
AddService appends a generic service request function
*/
func (s *GrpcServer) AddService(
	registerFunction func(*grpc.Server),
) {
	s.services = append(s.services, registerFunction)
}
