#ifndef SRC_CONFIG_SERVER_CONFIG_SERVER_H_
#define SRC_CONFIG_SERVER_CONFIG_SERVER_H_

#include "../../include/dv-sdk/cross/asio_tcptlssocket.hpp"
#include "../../include/dv-sdk/utils.h"

#include "../log.hpp"
#include "config_server_connection.h"

#include <atomic>
#include <memory>
#include <thread>
#include <vector>

class ConfigServer {
private:
	enum class IOThreadState {
		STARTING,
		RUNNING,
		STOPPING,
		STOPPED
	};

	static thread_local uint64_t currentClientID;

	bool ioThreadRun;
	IOThreadState ioThreadState;
	std::thread ioThread;
	asio::io_context ioService;
	asioTCP::acceptor acceptor;

	asioSSL::context tlsContext;
	bool tlsEnabled;

	std::vector<ConfigServerConnection *> clients;
	std::vector<ConfigServerConnection *> pushClients;
	std::atomic_size_t numPushClients;

	dv::LoggerInternal::LogBlock logger;

public:
	ConfigServer();
	~ConfigServer();

	ConfigServer(const ConfigServer &m) = delete;
	ConfigServer(ConfigServer &&m)      = delete;

	ConfigServer &operator=(const ConfigServer &rhs) = delete;
	ConfigServer &operator=(ConfigServer &&rhs)      = delete;

	void serviceConfigure();
	void threadStart();
	void threadStop();

	void setCurrentClientID(uint64_t clientID);
	uint64_t getCurrentClientID();
	void removeClient(ConfigServerConnection *client);
	void addPushClient(ConfigServerConnection *pushClient);
	void removePushClient(ConfigServerConnection *pushClient);
	bool pushClientsPresent();
	void pushMessageToClients(std::shared_ptr<const flatbuffers::FlatBufferBuilder> message);

private:
	void serviceStart();
	void serviceRestart();
	void serviceStop();
	void acceptStart();

	static void restartListener(dvConfigNode node, void *userData, enum dvConfigAttributeEvents event,
		const char *changeKey, enum dvConfigAttributeType changeType, union dvConfigAttributeValue changeValue);
	static void logLevelListener(dvConfigNode node, void *userData, enum dvConfigAttributeEvents event,
		const char *changeKey, enum dvConfigAttributeType changeType, union dvConfigAttributeValue changeValue);

	static void globalNodeChangeListener(
		dvConfigNode node, void *userData, enum dvConfigNodeEvents event, const char *changeNode);
	static void globalAttributeChangeListener(dvConfigNode node, void *userData, enum dvConfigAttributeEvents event,
		const char *changeKey, enum dvConfigAttributeType changeType, union dvConfigAttributeValue changeValue);
};

#endif /* SRC_CONFIG_SERVER_CONFIG_SERVER_H_ */
