#ifndef LIVOXPROTO1_CORE_H
#define LIVOXPROTO1_CORE_H

#include <vector>
#include <string>
#include <memory>
#include <cstdint>
#include <optional>
#include <user/senseApiDesc.h>
#include "device.h"
#include "broadcastListener.h"
#include "udpCommandDemuxer.h"
#include "livoxProto1.h"
#include <spinscale/co/invokers.h>

namespace livoxProto1 {

class DeviceManager
{
public:
	DeviceManager();
	~DeviceManager() = default;

	static void deviceGoneAwayInd(const comms::DiscoveredDevice &device);

	sscl::co::ViralNonPostingInvoker<LivoxProto1GetOrCreateDeviceResult>
	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);

	sscl::co::ViralNonPostingInvoker<bool> destroyDeviceCReq(
		std::shared_ptr<Device> device);

	std::optional<std::shared_ptr<Device>> getDevice(
		const std::string &deviceIdentifier);

	std::optional<std::shared_ptr<Device>> getDevice(
		const comms::DiscoveredDevice &device)
	{
		return getDevice(device.deviceIdentifier);
	}

private:
	// Configuration
	static constexpr int RETRY_DELAY_SECONDS = 3; // <N> seconds delay

public:
	std::vector<std::shared_ptr<Device>> devices;
	comms::BroadcastListener broadcastListener;
	comms::UdpCommandDemuxer udpCommandDemuxer;
};

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

// Global state structure
struct ProtoState
{
	bool isInitialized = false;
	std::shared_ptr<sscl::ComponentThread> componentThread;
	std::unique_ptr<DeviceManager> deviceManager;
	smo::stim_buff::SmoCallbacks smoCallbacks;
};

// Access to global state for extern "C" functions
ProtoState& getProtoState();

} // namespace livoxProto1

#endif // LIVOXPROTO1_CORE_H
