#ifndef _COMPUTE_MANAGER_H
#define _COMPUTE_MANAGER_H

#include <memory>
#include <vector>
#include <user/compute.h>

namespace smo {
namespace compute {

/**
 * @brief Centralized OpenCL platform and device management
 *
 * Enumerates all OpenCL platforms and devices, maintains contexts and command
 * queues, and provides methods to create buffers and access devices.
 */
class ComputeManager
{
public:
	static ComputeManager& getInstance()
	{
		static ComputeManager instance;
		return instance;
	}

	/**
	 * @brief Initialize ComputeManager by enumerating platforms and devices
	 *
	 * Enumerates all OpenCL platforms, then all devices on each platform,
	 * creating contexts and command queues for each device.
	 * Idempotent - can be called multiple times safely.
	 */
	void initialize();

	/**
	 * @brief Finalize ComputeManager, releasing all resources
	 *
	 * Releases all contexts, command queues, and clears device list.
	 * Safe to call even if not initialized.
	 */
	void finalize();

	/**
	 * @brief Create USE_HOST_PTR buffers on all contexts
	 *
	 * Creates a buffer using CL_MEM_USE_HOST_PTR on each device's context.
	 *
	 * @param hostPtr Host pointer to use
	 * @param size Size of buffer in bytes
	 * @param flags Additional OpenCL memory flags
	 * @return Shared pointer to ClBuffer managing buffers on all devices
	 */
	std::shared_ptr<ClBuffer> createUseHostPtrBuffer(
		void* hostPtr, size_t size, cl_mem_flags flags);

	/**
	 * @brief Release USE_HOST_PTR buffers
	 *
	 * Releases all buffers. This is a no-op since ClBuffer's destructor
	 * handles cleanup automatically.
	 *
	 * @param buffer Shared pointer to ClBuffer to release
	 */
	void releaseUseHostPtrBuffer(std::shared_ptr<ClBuffer> buffer);

	/**
	 * @brief Get a compute device
	 *
	 * Returns the first available device. Later will accept
	 * ComputeDeviceConstraints for filtering.
	 *
	 * @return Shared pointer to ComputeDevice, or nullptr if no devices available
	 */
	std::shared_ptr<ComputeDevice> getDevice();

	/**
	 * @brief Release a compute device
	 *
	 * Placeholder for future refcounting implementation.
	 * Currently a no-op - devices are only removed in finalize().
	 *
	 * @param device Shared pointer to ComputeDevice to release
	 */
	void releaseDevice(std::shared_ptr<ComputeDevice> device);

private:
	ComputeManager() : initialized(false) {}
	~ComputeManager() {}

	// Non-copyable, non-movable
	ComputeManager(const ComputeManager&) = delete;
	ComputeManager& operator=(const ComputeManager&) = delete;
	ComputeManager(ComputeManager&&) = delete;
	ComputeManager& operator=(ComputeManager&&) = delete;

	bool initialized;
	std::vector<std::shared_ptr<ComputeDevice>> devices;
};

} // namespace compute
} // namespace smo

#endif // _COMPUTE_MANAGER_H


