#ifndef _USER_SMO_HOOKS_H
#define _USER_SMO_HOOKS_H

#include <optional>
#include <string>
#include <memory>
#include <user/comparatorApiDesc.h>
#include <spinscale/componentThread.h>
#define CL_TARGET_OPENCL_VERSION 120
#include <CL/cl.h>

class OptionParser;

namespace smo {

namespace compute {
class ClBuffer;
class ComputeDevice;
} // namespace compute

namespace stim_buff {

/**
 * @brief Threading model descriptor for senseApi libraries.
 *
 * This structure provides senseApi libraries with access to the information and
 * resources they need to operate with SMO's threading model.
 */
struct SmoThreadingModelDesc
{
	/**
	 * @brief sh_ptr to ComponentThread for device-independent state mgt.
	 *
	 * This ComponentThread should be used by senseApis for state management
	 * that's independent of any particular device or attachment spec.
	 * SMO will usually pass in the Marionette thread here.
	 *
	 * State management that's tied to a particular attachment spec should be
	 * done on the ComponentThread passed to attachDeviceCReq. The attach and
	 * detach coroutines run on the thread named by ExplicitPostTarget (post-TO);
	 * SMO orchestration stays on the marionette thread.
	 */
	std::shared_ptr<sscl::ComponentThread> componentThread;
};

/**
 * @brief Hooks provided by Salmanoff to senseApi libraries.
 *
 * This structure contains function pointers that senseApi libraries can use
 * to interact with Salmanoff's functionality, such as searching for commonLibs.
 */
struct SmoCallbacks
{
	/**
	 * @brief Search for a library in Salmanoff's search paths
	 * @param libraryPath The relative filename of the library to search for
	 * @return Optional containing the full path if found, nullopt if not found
	 *
	 * This function searches for the given library in the same search paths
	 * that Salmanoff uses when loading senseApi libraries (user-specified
	 * paths via -p option, current directory, and executable directory).
	 */
	std::optional<std::string> (*searchForLibInSmoSearchPaths)(
		const std::string& libraryPath);

	/**
	 * @brief Get the current ComponentThread instance
	 * @return Shared pointer to the current ComponentThread
	 *
	 * This function provides access to the current ComponentThread instance,
	 * equivalent to calling sscl::ComponentThread::getSelf().
	 */
	std::shared_ptr<sscl::ComponentThread> (*ComponentThread_getSelf)(void);

	/**
	 * @brief Get the OptionParser singleton instance
	 * @return Reference to the OptionParser singleton
	 *
	 * This function provides access to the OptionParser singleton instance,
	 * equivalent to calling OptionParser::getOptions().
	 */
	OptionParser& (*OptionParser_getOptions)(void);

	/**
	 * @brief Create a USE_HOST_PTR buffer on all OpenCL contexts
	 * @param hostPtr Host pointer to the memory
	 * @param size Size of the buffer in bytes
	 * @param flags Additional OpenCL memory flags
	 * @return Shared pointer to ClBuffer managing buffers on all devices
	 */
	std::shared_ptr<smo::compute::ClBuffer>
	(*ComputeManager_createUseHostPtrBuffer)(
		void* hostPtr, size_t size, cl_mem_flags flags);

	/**
	 * @brief Release USE_HOST_PTR buffers from all contexts
	 * @param buffer Shared pointer to ClBuffer to release
	 */
	void (*ComputeManager_releaseUseHostPtrBuffer)(
		std::shared_ptr<smo::compute::ClBuffer> buffer);

	/**
	 * @brief Get a compute device
	 * @return Shared pointer to ComputeDevice, or nullptr if no devices available
	 */
	std::shared_ptr<smo::compute::ComputeDevice>
	(*ComputeManager_getDevice)(void);

	/**
	 * @brief Release a compute device
	 * @param device Shared pointer to ComputeDevice to release
	 */
	void (*ComputeManager_releaseDevice)(
		std::shared_ptr<smo::compute::ComputeDevice> device);

	std::shared_ptr<cologex::ExportedComparatorTypeDesc>
	(*ComparatorManager_getComparatorType)(
		cologex::ComparatorTypeId typeId);

	std::unique_ptr<cologex::Comparator> (*Comparator_getNewInstance)(
		const std::shared_ptr<cologex::ExportedComparatorTypeDesc>&
			comparatorType);
};

const SmoCallbacks& getSmoCallbacks();

} // namespace stim_buff
} // namespace smo

#endif // _USER_SMO_HOOKS_H
