/*
 * Copyright 2015 - 2025 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#pragma once

#ifdef OX_USE_STDLIB
#include <condition_variable>
#include <mutex>
#include <thread>
#endif

#include <ox/mc/write.hpp>
#include <ox/std/trace.hpp>

#include "circularbuff.hpp"

namespace ox {

#ifdef OX_USE_STDLIB
class LoggerConn: public trace::Logger {
	private:
		int m_socket = 0;
		detail::CirculerBuffer m_buff;
		std::thread m_netThread;
		std::condition_variable m_waitCond;
		std::mutex m_waitMut;
		std::mutex m_buffMut;
		bool m_running = true;
	public:
		LoggerConn() noexcept;
		LoggerConn(const LoggerConn&) noexcept = delete;
		~LoggerConn() noexcept override;
		LoggerConn &operator=(const LoggerConn&) noexcept = delete;
		ox::Error send(const trace::TraceMsg&) noexcept final;
		ox::Error sendInit(const trace::InitTraceMsg&) noexcept final;
		ox::Error initConn(ox::StringViewCR appName) noexcept;
		ox::Error send(const char *buff, std::size_t len) const noexcept;
	private:
		void msgSend() noexcept;
		ox::Error send(trace::MsgId msgId, const auto &msg) noexcept {
			ox::Array<char, 10 * ox::units::KB> buff;
			std::size_t sz = 0;
			OX_RETURN_ERROR(ox::writeMC(&buff[0], buff.size(), msg, &sz));
			//std::printf("sz: %lu\n", sz);
			OX_REQUIRE(szBuff, serialize(static_cast<uint32_t>(sz)));
			std::unique_lock buffLk(m_buffMut);
			OX_RETURN_ERROR(m_buff.put(static_cast<char>(msgId)));
			OX_RETURN_ERROR(m_buff.write(szBuff.data(), szBuff.size()));
			OX_RETURN_ERROR(m_buff.write(buff.data(), sz));
			buffLk.unlock();
			m_waitCond.notify_one();
			return {};
		}

};

#else

class LoggerConn: public trace::Logger {
	private:
	public:
		constexpr LoggerConn() noexcept = default;
		LoggerConn(const LoggerConn&) noexcept = delete;
		constexpr ~LoggerConn() noexcept override = default;
		LoggerConn &operator=(const LoggerConn&) noexcept = delete;
		ox::Error send(const trace::TraceMsg&) noexcept final { return {}; }
		static ox::Error initConn() noexcept { return {}; }
		static ox::Error send(const char*, std::size_t) noexcept { return {}; }
};
#endif

}

