// Copyright 2004-present Facebook. All Rights Reserved.

#pragma once

#include <chrono>
#include <condition_variable>
#include <mutex>
#include <queue>

#include <folly/Function.h>
#include <folly/Optional.h>
#include <hermes/hermes.h>
#include <hermes/inspector/chrome/Connection.h>

namespace facebook {
namespace hermes {
namespace inspector {
namespace chrome {

/**
 * SyncConnection provides a synchronous interface over Connection that is
 * useful in tests.
 */
class SyncConnection {
 public:
  SyncConnection(std::shared_ptr<HermesRuntime> runtime);
  ~SyncConnection() = default;

  /// sends a message to the debugger
  void send(const std::string &str);

  /// waits for the next response from the debugger. handler is called with the
  /// response. throws on timeout.
  void waitForResponse(
      folly::Function<void(const std::string &)> handler,
      std::chrono::milliseconds timeout = std::chrono::milliseconds(2500));

  /// waits for the next notification from the debugger. handler is called with
  /// the notification. throws on timeout.
  void waitForNotification(
      folly::Function<void(const std::string &)> handler,
      std::chrono::milliseconds timeout = std::chrono::milliseconds(2500));

 private:
  class RemoteConnnection;
  friend class RemoteConnnection;

  void onReply(const std::string &message);

  Connection connection_;

  std::mutex mutex_;
  std::condition_variable hasReply_;
  std::queue<std::string> replies_;
  std::condition_variable hasNotification_;
  std::queue<std::string> notifications_;
};

} // namespace chrome
} // namespace inspector
} // namespace hermes
} // namespace facebook
