#include "EggDuino.h"

namespace {
constexpr size_t kLogCapacity = 80;
constexpr size_t kLogLineLength = 160;

char g_logLines[kLogCapacity][kLogLineLength];
uint32_t g_logSeq[kLogCapacity];
size_t g_logWritePos = 0;
uint32_t g_nextLogSeq = 1;

void appendJsonEscaped(String &out, const char *text) {
	out += "\"";
	for (size_t i = 0; text[i] != '\0'; ++i) {
		const char c = text[i];
		switch (c) {
			case '\\':
				out += "\\\\";
				break;
			case '"':
				out += "\\\"";
				break;
			case '\n':
				out += "\\n";
				break;
			case '\r':
				out += "\\r";
				break;
			case '\t':
				out += "\\t";
				break;
			default:
				if (static_cast<unsigned char>(c) < 0x20) {
					out += '?';
				} else {
					out += c;
				}
				break;
		}
	}
	out += "\"";
}
} // namespace

void Log(const String &message) {
	snprintf(
		g_logLines[g_logWritePos],
		kLogLineLength,
		"[%010lu] %s",
		static_cast<unsigned long>(millis()),
		message.c_str()
	);
	g_logSeq[g_logWritePos] = g_nextLogSeq++;
	g_logWritePos = (g_logWritePos + 1) % kLogCapacity;
}

void Log(const char *message) {
	Log(String(message));
}

String buildLogsJson(uint32_t sinceSeq) {
	String output;
	output.reserve(2048);
	output += "{\"logs\":[";
	uint32_t lastSeq = sinceSeq;
	bool first = true;

	for (size_t i = 0; i < kLogCapacity; ++i) {
		const size_t idx = (g_logWritePos + i) % kLogCapacity;
		const uint32_t seq = g_logSeq[idx];
		if (seq == 0 || seq <= sinceSeq) {
			continue;
		}

		if (!first) {
			output += ",";
		}
		first = false;
		output += "{\"seq\":";
		output += String(seq);
		output += ",\"text\":";
		appendJsonEscaped(output, g_logLines[idx]);
		output += "}";
		lastSeq = seq;
	}

	output += "],\"lastSeq\":";
	output += String(lastSeq);
	output += "}";
	return output;
}
