//
//
// Copyright 2015 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.
//
//

#include <list>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <thread>
#include <utility>
#include <vector>

#include "absl/memory/memory.h"

#include <grpc/grpc.h>
#include <grpc/support/cpu.h>
#include <grpc/support/log.h>
#include <grpcpp/alarm.h>
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>

#include "src/core/lib/gprpp/crash.h"
#include "src/proto/grpc/testing/benchmark_service.grpc.pb.h"
#include "test/cpp/qps/client.h"
#include "test/cpp/qps/usage_timer.h"

namespace grpc {
namespace testing {

///
/// Maintains context info per RPC
///
struct CallbackClientRpcContext {
  explicit CallbackClientRpcContext(BenchmarkService::Stub* stub)
      : alarm_(nullptr), stub_(stub) {}

  ~CallbackClientRpcContext() {}

  SimpleResponse response_;
  ClientContext context_;
  std::unique_ptr<Alarm> alarm_;
  BenchmarkService::Stub* stub_;
};

static std::unique_ptr<BenchmarkService::Stub> BenchmarkStubCreator(
    const std::shared_ptr<Channel>& ch) {
  return BenchmarkService::NewStub(ch);
}

class CallbackClient
    : public ClientImpl<BenchmarkService::Stub, SimpleRequest> {
 public:
  explicit CallbackClient(const ClientConfig& config)
      : ClientImpl<BenchmarkService::Stub, SimpleRequest>(
            config, BenchmarkStubCreator) {
    num_threads_ = NumThreads(config);
    rpcs_done_ = 0;

    //  Don't divide the fixed load among threads as the user threads
    //  only bootstrap the RPCs
    SetupLoadTest(config, 1);
    total_outstanding_rpcs_ =
        config.client_channels() * config.outstanding_rpcs_per_channel();
  }

  ~CallbackClient() override {}

  ///
  /// The main thread of the benchmark will be waiting on DestroyMultithreading.
  /// Increment the rpcs_done_ variable to signify that the Callback RPC
  /// after thread completion is done. When the last outstanding rpc increments
  /// the counter it should also signal the main thread's conditional variable.
  ///
  void NotifyMainThreadOfThreadCompletion() {
    std::lock_guard<std::mutex> l(shutdown_mu_);
    rpcs_done_++;
    if (rpcs_done_ == total_outstanding_rpcs_) {
      shutdown_cv_.notify_one();
    }
  }

  gpr_timespec NextRPCIssueTime() {
    std::lock_guard<std::mutex> l(next_issue_time_mu_);
    return Client::NextIssueTime(0);
  }

 protected:
  size_t num_threads_;
  size_t total_outstanding_rpcs_;
  // The below mutex and condition variable is used by main benchmark thread to
  // wait on completion of all RPCs before shutdown
  std::mutex shutdown_mu_;
  std::condition_variable shutdown_cv_;
  // Number of rpcs done after thread completion
  size_t rpcs_done_;
  // Vector of Context data pointers for running a RPC
  std::vector<std::unique_ptr<CallbackClientRpcContext>> ctx_;

  virtual void InitThreadFuncImpl(size_t thread_idx) = 0;
  virtual bool ThreadFuncImpl(Thread* t, size_t thread_idx) = 0;

  void ThreadFunc(size_t thread_idx, Thread* t) override {
    InitThreadFuncImpl(thread_idx);
    ThreadFuncImpl(t, thread_idx);
  }

 private:
  std::mutex next_issue_time_mu_;  // Used by next issue time

  int NumThreads(const ClientConfig& config) {
    int num_threads = config.async_client_threads();
    if (num_threads <= 0) {  // Use dynamic sizing
      num_threads = cores_;
      gpr_log(GPR_INFO, "Sizing callback client to %d threads", num_threads);
    }
    return num_threads;
  }

  ///
  /// Wait until all outstanding Callback RPCs are done
  ///
  void DestroyMultithreading() final {
    std::unique_lock<std::mutex> l(shutdown_mu_);
    while (rpcs_done_ != total_outstanding_rpcs_) {
      shutdown_cv_.wait(l);
    }
    EndThreads();
  }
};

class CallbackUnaryClient final : public CallbackClient {
 public:
  explicit CallbackUnaryClient(const ClientConfig& config)
      : CallbackClient(config) {
    for (int ch = 0; ch < config.client_channels(); ch++) {
      for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) {
        ctx_.emplace_back(
            new CallbackClientRpcContext(channels_[ch].get_stub()));
      }
    }
    StartThreads(num_threads_);
  }
  ~CallbackUnaryClient() override {}

 protected:
  bool ThreadFuncImpl(Thread* t, size_t thread_idx) override {
    for (size_t vector_idx = thread_idx; vector_idx < total_outstanding_rpcs_;
         vector_idx += num_threads_) {
      ScheduleRpc(t, vector_idx);
    }
    return true;
  }

  void InitThreadFuncImpl(size_t /*thread_idx*/) override {}

 private:
  void ScheduleRpc(Thread* t, size_t vector_idx) {
    if (!closed_loop_) {
      gpr_timespec next_issue_time = NextRPCIssueTime();
      // Start an alarm callback to run the internal callback after
      // next_issue_time
      if (ctx_[vector_idx]->alarm_ == nullptr) {
        ctx_[vector_idx]->alarm_ = std::make_unique<Alarm>();
      }
      ctx_[vector_idx]->alarm_->Set(next_issue_time,
                                    [this, t, vector_idx](bool /*ok*/) {
                                      IssueUnaryCallbackRpc(t, vector_idx);
                                    });
    } else {
      IssueUnaryCallbackRpc(t, vector_idx);
    }
  }

  void IssueUnaryCallbackRpc(Thread* t, size_t vector_idx) {
    double start = UsageTimer::Now();
    ctx_[vector_idx]->stub_->async()->UnaryCall(
        (&ctx_[vector_idx]->context_), &request_, &ctx_[vector_idx]->response_,
        [this, t, start, vector_idx](grpc::Status s) {
          // Update Histogram with data from the callback run
          HistogramEntry entry;
          if (s.ok()) {
            entry.set_value((UsageTimer::Now() - start) * 1e9);
          }
          entry.set_status(s.error_code());
          t->UpdateHistogram(&entry);

          if (ThreadCompleted() || !s.ok()) {
            // Notify thread of completion
            NotifyMainThreadOfThreadCompletion();
          } else {
            // Reallocate ctx for next RPC
            ctx_[vector_idx] = std::make_unique<CallbackClientRpcContext>(
                ctx_[vector_idx]->stub_);
            // Schedule a new RPC
            ScheduleRpc(t, vector_idx);
          }
        });
  }
};

class CallbackStreamingClient : public CallbackClient {
 public:
  explicit CallbackStreamingClient(const ClientConfig& config)
      : CallbackClient(config),
        messages_per_stream_(config.messages_per_stream()) {
    for (int ch = 0; ch < config.client_channels(); ch++) {
      for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) {
        ctx_.emplace_back(
            new CallbackClientRpcContext(channels_[ch].get_stub()));
      }
    }
    StartThreads(num_threads_);
  }
  ~CallbackStreamingClient() override {}

  void AddHistogramEntry(double start, bool ok, Thread* thread_ptr) {
    // Update Histogram with data from the callback run
    HistogramEntry entry;
    if (ok) {
      entry.set_value((UsageTimer::Now() - start) * 1e9);
    }
    thread_ptr->UpdateHistogram(&entry);
  }

  int messages_per_stream() { return messages_per_stream_; }

 protected:
  const int messages_per_stream_;
};

class CallbackStreamingPingPongClient : public CallbackStreamingClient {
 public:
  explicit CallbackStreamingPingPongClient(const ClientConfig& config)
      : CallbackStreamingClient(config) {}
  ~CallbackStreamingPingPongClient() override {}
};

class CallbackStreamingPingPongReactor final
    : public grpc::ClientBidiReactor<SimpleRequest, SimpleResponse> {
 public:
  CallbackStreamingPingPongReactor(
      CallbackStreamingPingPongClient* client,
      std::unique_ptr<CallbackClientRpcContext> ctx)
      : client_(client), ctx_(std::move(ctx)), messages_issued_(0) {}

  void StartNewRpc() {
    ctx_->stub_->async()->StreamingCall(&(ctx_->context_), this);
    write_time_ = UsageTimer::Now();
    StartWrite(client_->request());
    writes_done_started_.clear();
    StartCall();
  }

  void OnWriteDone(bool ok) override {
    if (!ok) {
      gpr_log(GPR_ERROR, "Error writing RPC");
    }
    if ((!ok || client_->ThreadCompleted()) &&
        !writes_done_started_.test_and_set()) {
      StartWritesDone();
    }
    StartRead(&ctx_->response_);
  }

  void OnReadDone(bool ok) override {
    client_->AddHistogramEntry(write_time_, ok, thread_ptr_);

    if (client_->ThreadCompleted() || !ok ||
        (client_->messages_per_stream() != 0 &&
         ++messages_issued_ >= client_->messages_per_stream())) {
      if (!ok) {
        gpr_log(GPR_ERROR, "Error reading RPC");
      }
      if (!writes_done_started_.test_and_set()) {
        StartWritesDone();
      }
      return;
    }
    if (!client_->IsClosedLoop()) {
      gpr_timespec next_issue_time = client_->NextRPCIssueTime();
      // Start an alarm callback to run the internal callback after
      // next_issue_time
      ctx_->alarm_->Set(next_issue_time, [this](bool /*ok*/) {
        write_time_ = UsageTimer::Now();
        StartWrite(client_->request());
      });
    } else {
      write_time_ = UsageTimer::Now();
      StartWrite(client_->request());
    }
  }

  void OnDone(const Status& s) override {
    if (client_->ThreadCompleted() || !s.ok()) {
      client_->NotifyMainThreadOfThreadCompletion();
      return;
    }
    ctx_ = std::make_unique<CallbackClientRpcContext>(ctx_->stub_);
    ScheduleRpc();
  }

  void ScheduleRpc() {
    if (!client_->IsClosedLoop()) {
      gpr_timespec next_issue_time = client_->NextRPCIssueTime();
      // Start an alarm callback to run the internal callback after
      // next_issue_time
      if (ctx_->alarm_ == nullptr) {
        ctx_->alarm_ = std::make_unique<Alarm>();
      }
      ctx_->alarm_->Set(next_issue_time,
                        [this](bool /*ok*/) { StartNewRpc(); });
    } else {
      StartNewRpc();
    }
  }

  void set_thread_ptr(Client::Thread* ptr) { thread_ptr_ = ptr; }

  CallbackStreamingPingPongClient* client_;
  std::unique_ptr<CallbackClientRpcContext> ctx_;
  std::atomic_flag writes_done_started_;
  Client::Thread* thread_ptr_;  // Needed to update histogram entries
  double write_time_;           // Track ping-pong round start time
  int messages_issued_;         // Messages issued by this stream
};

class CallbackStreamingPingPongClientImpl final
    : public CallbackStreamingPingPongClient {
 public:
  explicit CallbackStreamingPingPongClientImpl(const ClientConfig& config)
      : CallbackStreamingPingPongClient(config) {
    for (size_t i = 0; i < total_outstanding_rpcs_; i++) {
      reactor_.emplace_back(
          new CallbackStreamingPingPongReactor(this, std::move(ctx_[i])));
    }
  }
  ~CallbackStreamingPingPongClientImpl() override {}

  bool ThreadFuncImpl(Client::Thread* t, size_t thread_idx) override {
    for (size_t vector_idx = thread_idx; vector_idx < total_outstanding_rpcs_;
         vector_idx += num_threads_) {
      reactor_[vector_idx]->set_thread_ptr(t);
      reactor_[vector_idx]->ScheduleRpc();
    }
    return true;
  }

  void InitThreadFuncImpl(size_t /*thread_idx*/) override {}

 private:
  std::vector<std::unique_ptr<CallbackStreamingPingPongReactor>> reactor_;
};

// TODO(mhaidry) : Implement Streaming from client, server and both ways

std::unique_ptr<Client> CreateCallbackClient(const ClientConfig& config) {
  switch (config.rpc_type()) {
    case UNARY:
      return std::unique_ptr<Client>(new CallbackUnaryClient(config));
    case STREAMING:
      return std::unique_ptr<Client>(
          new CallbackStreamingPingPongClientImpl(config));
    case STREAMING_FROM_CLIENT:
    case STREAMING_FROM_SERVER:
    case STREAMING_BOTH_WAYS:
      grpc_core::Crash(
          "STREAMING_FROM_* scenarios are not supported by the callback "
          "API");
    default:
      grpc_core::Crash(absl::StrCat("Unknown RPC type: ", config.rpc_type()));
  }
}

}  // namespace testing
}  // namespace grpc
