#include "MockIO.hpp"

namespace celuna::tests {

void MockIO::publish(const std::string& topic, std::unique_ptr<grove::IDataNode> data) {
    // Convert IDataNode to JSON for easy verification
    json jsonData;

    if (data) {
        // Try to extract JSON from JsonDataNode
        auto* jsonNode = dynamic_cast<grove::JsonDataNode*>(data.get());
        if (jsonNode) {
            jsonData = jsonNode->getJsonData();
        } else {
            // Fallback: create basic JSON from IDataNode interface
            jsonData = json::object();
        }
    }

    m_publishedMessages.emplace_back(topic, jsonData);
}

grove::Message MockIO::pullMessage() {
    if (m_incomingMessages.empty()) {
        throw std::runtime_error("No messages available");
    }

    grove::Message msg = std::move(m_incomingMessages.front());
    m_incomingMessages.pop();
    return msg;
}

void MockIO::injectMessage(const std::string& topic, const json& data) {
    grove::Message message;
    message.topic = topic;
    message.data = std::make_unique<grove::JsonDataNode>("data", data);
    message.timestamp = 0;
    m_incomingMessages.push(std::move(message));
}

void MockIO::injectMessages(const std::vector<std::pair<std::string, json>>& messages) {
    for (const auto& [topic, data] : messages) {
        injectMessage(topic, data);
    }
}

bool MockIO::wasPublished(const std::string& topic) const {
    return std::any_of(m_publishedMessages.begin(), m_publishedMessages.end(),
        [&topic](const auto& msg) { return msg.first == topic; });
}

json MockIO::getLastPublished(const std::string& topic) const {
    for (auto it = m_publishedMessages.rbegin(); it != m_publishedMessages.rend(); ++it) {
        if (it->first == topic) {
            return it->second;
        }
    }
    return json::object();
}

std::vector<json> MockIO::getAllPublished(const std::string& topic) const {
    std::vector<json> result;
    for (const auto& [t, data] : m_publishedMessages) {
        if (t == topic) {
            result.push_back(data);
        }
    }
    return result;
}

size_t MockIO::countPublished(const std::string& topic) const {
    return std::count_if(m_publishedMessages.begin(), m_publishedMessages.end(),
        [&topic](const auto& msg) { return msg.first == topic; });
}

void MockIO::clear() {
    m_publishedMessages.clear();
    while (!m_incomingMessages.empty()) {
        m_incomingMessages.pop();
    }
    m_subscriptions.clear();
}

void MockIO::clearPublished() {
    m_publishedMessages.clear();
}

} // namespace celuna::tests
