/*
 *
 * Copyright 2019 gRPC authors.
 *
 * 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 service defines methods to register a gRPC client/service for a
// profiling service that is exposed in the same server. This service can be
// queried by a client to remotely manage the gRPC profiling behaviour of an
// application.
//
// Experimental
//
// Notice: This package is EXPERIMENTAL and may be changed or removed in a
// later release.
package service

import (
	"context"
	"errors"
	"sync"

	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
	"google.golang.org/grpc/internal/profiling"
	ppb "google.golang.org/grpc/profiling/proto"
)

var logger = grpclog.Component("profiling")

// ProfilingConfig defines configuration options for the Init method.
type ProfilingConfig struct {
	// Setting this to true will enable profiling.
	Enabled bool

	// Profiling uses a circular buffer (ring buffer) to store statistics for
	// only the last few RPCs so that profiling stats do not grow unbounded. This
	// parameter defines the upper limit on the number of RPCs for which
	// statistics should be stored at any given time. An average RPC requires
	// approximately 2-3 KiB of memory for profiling-related statistics, so
	// choose an appropriate number based on the amount of memory you can afford.
	StreamStatsSize uint32

	// To expose the profiling service and its methods, a *grpc.Server must be
	// provided.
	Server *grpc.Server
}

var errorNilServer = errors.New("profiling: no grpc.Server provided")

// Init takes a *ProfilingConfig to initialize profiling (turned on/off
// depending on the value set in pc.Enabled) and register the profiling service
// in the server provided in pc.Server.
func Init(pc *ProfilingConfig) error {
	if pc.Server == nil {
		return errorNilServer
	}

	if err := profiling.InitStats(pc.StreamStatsSize); err != nil {
		return err
	}

	ppb.RegisterProfilingServer(pc.Server, getProfilingServerInstance())

	// Do this last after everything has been initialized and allocated.
	profiling.Enable(pc.Enabled)

	return nil
}

type profilingServer struct {
	ppb.UnimplementedProfilingServer
	drainMutex sync.Mutex
}

var profilingServerInstance *profilingServer
var profilingServerOnce sync.Once

// getProfilingServerInstance creates and returns a singleton instance of
// profilingServer. Only one instance of profilingServer is created to use a
// shared mutex across all profilingServer instances.
func getProfilingServerInstance() *profilingServer {
	profilingServerOnce.Do(func() {
		profilingServerInstance = &profilingServer{}
	})

	return profilingServerInstance
}

func (s *profilingServer) Enable(ctx context.Context, req *ppb.EnableRequest) (*ppb.EnableResponse, error) {
	if req.Enabled {
		logger.Infof("profilingServer: Enable: enabling profiling")
	} else {
		logger.Infof("profilingServer: Enable: disabling profiling")
	}
	profiling.Enable(req.Enabled)

	return &ppb.EnableResponse{}, nil
}

func timerToProtoTimer(timer *profiling.Timer) *ppb.Timer {
	return &ppb.Timer{
		Tags:      timer.Tags,
		BeginSec:  timer.Begin.Unix(),
		BeginNsec: int32(timer.Begin.Nanosecond()),
		EndSec:    timer.End.Unix(),
		EndNsec:   int32(timer.End.Nanosecond()),
		GoId:      timer.GoID,
	}
}

func statToProtoStat(stat *profiling.Stat) *ppb.Stat {
	protoStat := &ppb.Stat{
		Tags:     stat.Tags,
		Timers:   make([]*ppb.Timer, 0, len(stat.Timers)),
		Metadata: stat.Metadata,
	}
	for _, t := range stat.Timers {
		protoStat.Timers = append(protoStat.Timers, timerToProtoTimer(t))
	}
	return protoStat
}

func (s *profilingServer) GetStreamStats(ctx context.Context, req *ppb.GetStreamStatsRequest) (*ppb.GetStreamStatsResponse, error) {
	// Since the drain operation is destructive, only one client request should
	// be served at a time.
	logger.Infof("profilingServer: GetStreamStats: processing request")
	s.drainMutex.Lock()
	results := profiling.StreamStats.Drain()
	s.drainMutex.Unlock()

	logger.Infof("profilingServer: GetStreamStats: returning %v records", len(results))
	streamStats := make([]*ppb.Stat, 0)
	for _, stat := range results {
		streamStats = append(streamStats, statToProtoStat(stat.(*profiling.Stat)))
	}
	return &ppb.GetStreamStatsResponse{StreamStats: streamStats}, nil
}
