/**
 * @file BlockingApi.hpp
 *
 * @brief Header file that declares the blocking API
 */

#pragma once

#include <condition_variable>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <vector>

class BlockingApi {
public:
  /**
   * The function passed to the execute method takes a vector of bytes as input
   */
  using CallbackFunction = std::function<bool()>;

  /**
   * Constructor: initializes the BlockingApi
   * @param timeout Timeout in milliseconds for operations. Use -1 for no timeout
   */
  BlockingApi(int timeout = -1);

  /**
   * Sets the timeout for the blocking API
   * @param newTimeout The new timeout in milliseconds (-1 means no timeout)
   */
  void setTimeout(int newTimeout);

  /**
   * Executes a function and waits for a response
   * @param function The function to execute
   * @param input The input data to pass to the function
   * @return true if the response was received, false if it timed out
   */
  bool execute(CallbackFunction function);

  /**
   * Notifies that a response has been received
   * This function should be called when a response arrives
   */
  void notifyResponseReceived();

#ifdef __wasm__
  /**
   * Sets the poll function used in WASM mode.
   * This function is called in a loop by waitForResponse() instead of
   * blocking on a condition variable. It should call CosmicDriver::pollOnce()
   * which yields to the browser event loop via ASYNCIFY.
   * @param fn The poll function (typically bound to CosmicDriver::pollOnce)
   */
  void setPollDriver(std::function<void()> fn);
#endif

private:
  // Timeout in milliseconds (-1 means no timeout)
  int timeout;

  // Variables for tracking purposes
  bool messageReceivedFlag{false};
  std::condition_variable messageReceived;

  // Mutex for thread safety
  std::mutex locking;

#ifdef __wasm__
  // Poll function for WASM mode — calls CosmicDriver::pollOnce()
  std::function<void()> pollDriver;
#endif

  /**
   * Waits for a response to be received
   * @return true if the response was received, false if it timed out
   */
  bool waitForResponse();
};