#include <stdexcept>
#include <boost/asio/posix/stream_descriptor.hpp>
#include "livoxProto1.h"
#include "device.h"
#include "core.h"
#include "udpCommandDemuxer.h"


extern "C" {

sscl::co::ViralNonPostingInvoker<LivoxProto1GetOrCreateDeviceResult>
livoxProto1_getOrCreateDeviceCReq(
	const std::string& deviceIdentifier,
	const std::shared_ptr<sscl::ComponentThread>& componentThread,
	int commandTimeoutMs, int retryDelayMs,
	const std::string& smoIp, uint8_t smoSubnetNbits,
	uint16_t dataPort, uint16_t cmdPort, uint16_t imuPort)
{
	// Get the global DeviceManager instance
	auto& protoState = livoxProto1::getProtoState();
	if (!protoState.deviceManager)
	{
		throw std::runtime_error(
			std::string(__func__) + ": LivoxProto1 not initialized - call "
			"livoxProto1_main first");
	}

	// Delegate to the DeviceManager to create the device
	co_return co_await protoState.deviceManager->getOrCreateDeviceCReq(
		deviceIdentifier, componentThread,
		commandTimeoutMs, retryDelayMs,
		smoIp, smoSubnetNbits,
		dataPort, cmdPort, imuPort);
}

sscl::co::ViralNonPostingInvoker<bool> livoxProto1_destroyDeviceCReq(
	std::shared_ptr<livoxProto1::Device> device)
{
	auto& protoState = livoxProto1::getProtoState();
	if (!protoState.deviceManager)
	{
		throw std::runtime_error(std::string(__func__)
			+ ": DeviceManager not initialized");
	}

	co_return co_await protoState.deviceManager->destroyDeviceCReq(device);
}

void livoxProto1_main(
	const std::shared_ptr<sscl::ComponentThread>& componentThread,
	const smo::stim_buff::SmoCallbacks& smoCallbacks)
{
	livoxProto1::main(componentThread, smoCallbacks);
}

void livoxProto1_exit(void)
{
	livoxProto1::exit();
}

sscl::co::ViralNonPostingInvoker<bool> livoxProto1_device_enablePcloudDataCReq(
	std::shared_ptr<livoxProto1::Device> device)
{
	if (!device)
	{
		throw std::runtime_error(std::string(__func__)
			+ ": Device pointer is null");
	}

	co_return co_await device->enablePcloudDataCReq();
}

sscl::co::ViralNonPostingInvoker<bool> livoxProto1_device_disablePcloudDataCReq(
	std::shared_ptr<livoxProto1::Device> device)
{
	if (!device)
	{
		throw std::runtime_error(std::string(__func__)
			+ ": Device pointer is null");
	}

	co_return co_await device->disablePcloudDataCReq();
}

sscl::co::ViralNonPostingInvoker<LivoxProto1GetReturnModeResult>
livoxProto1_device_getReturnModeCReq(
	std::shared_ptr<livoxProto1::Device> device)
{
	if (!device)
	{
		throw std::runtime_error(std::string(__func__)
			+ ": Device pointer is null");
	}

	livoxProto1::Device::GetReturnModeResult deviceResult =
		co_await device->getReturnModeCReq();
	LivoxProto1GetReturnModeResult result;
	result.success = deviceResult.success;
	result.returnMode = deviceResult.returnMode;
	co_return result;
}

std::shared_ptr<boost::asio::posix::stream_descriptor>
livoxProto1_getPcloudDataFdDesc(void)
{
	auto& protoState = livoxProto1::getProtoState();
	if (!protoState.deviceManager)
	{
		throw std::runtime_error(std::string(__func__)
			+ ": DeviceManager not initialized");
	}

	return protoState.deviceManager->udpCommandDemuxer.getPcloudDataFdDesc();
}

} // extern "C"
