#include "StorageModule.h"
#include <grove/IIO.h>
#include <grove/JsonDataNode.h>
#include <sstream>
#include <iomanip>

namespace celuna {

StorageModule::StorageModule() {
    m_logger = spdlog::get("StorageModule");
    if (!m_logger) {
        m_logger = spdlog::stdout_color_mt("StorageModule");
    }
    m_config = std::make_unique<grove::JsonDataNode>("config");
}

void StorageModule::setConfiguration(const grove::IDataNode& configNode,
                                     grove::IIO* io,
                                     grove::ITaskScheduler* scheduler) {
    m_io = io;
    m_config = std::make_unique<grove::JsonDataNode>("config");

    // Subscribe to topics
    if (m_io) {
        grove::SubscriptionConfig subConfig;
        m_io->subscribe("scheduler:task_completed", subConfig);
        m_io->subscribe("monitoring:app_changed", subConfig);
        m_io->subscribe("storage:session_saved", subConfig);
        m_io->subscribe("storage:error", subConfig);
        // Tool request handlers
        m_io->subscribe("storage:query", subConfig);
        m_io->subscribe("storage:command", subConfig);
    }

    m_logger->info("StorageModule configure (v2 - sans infrastructure)");
}

const grove::IDataNode& StorageModule::getConfiguration() {
    return *m_config;
}

void StorageModule::process(const grove::IDataNode& input) {
    processMessages();
}

void StorageModule::processMessages() {
    if (!m_io) return;

    while (m_io->hasMessages() > 0) {
        auto msg = m_io->pullMessage();

        if (msg.topic == "scheduler:task_completed" && msg.data) {
            handleTaskCompleted(*msg.data);
        }
        else if (msg.topic == "monitoring:app_changed" && msg.data) {
            handleAppChanged(*msg.data);
        }
        else if (msg.topic == "storage:session_saved" && msg.data) {
            handleSessionSaved(*msg.data);
        }
        else if (msg.topic == "storage:error" && msg.data) {
            handleStorageError(*msg.data);
        }
        // Tool handlers
        else if (msg.topic == "storage:query" && msg.data) {
            handleToolQuery(*msg.data);
        }
        else if (msg.topic == "storage:command" && msg.data) {
            handleToolCommand(*msg.data);
        }
    }
}

void StorageModule::handleToolQuery(const grove::IDataNode& request) {
    std::string correlationId = request.getString("correlation_id", "");
    std::string action = request.getString("action", "");

    auto response = std::make_unique<grove::JsonDataNode>("response");
    response->setString("correlation_id", correlationId);

    if (action == "query_notes") {
        std::string query = request.getString("query", "");
        std::string tag = request.getString("tag", "");
        int limit = request.getInt("limit", 10);

        // Search in-memory notes
        int count = 0;
        for (const auto& note : m_notes) {
            if (count >= limit) break;

            bool matches = query.empty() ||
                           note.content.find(query) != std::string::npos;

            if (!tag.empty()) {
                bool hasTag = false;
                for (const auto& t : note.tags) {
                    if (t == tag) { hasTag = true; break; }
                }
                matches = matches && hasTag;
            }

            if (matches) {
                auto noteNode = std::make_unique<grove::JsonDataNode>("note_" + std::to_string(count));
                noteNode->setString("id", note.id);
                noteNode->setString("content", note.content);
                noteNode->setString("timestamp", note.timestamp);
                response->setChild("note_" + std::to_string(count), std::move(noteNode));
                count++;
            }
        }
        response->setInt("count", count);
    }
    else if (action == "get_session_history") {
        int days = request.getInt("days", 7);
        response->setInt("last_session_id", m_lastSessionId);
        response->setInt("total_saved", m_totalSaved);
        response->setString("note", "Full history requires StorageService query");
    }
    else {
        response->setString("error", "unknown_action");
    }

    m_io->publish("storage:response", std::move(response));
}

void StorageModule::handleToolCommand(const grove::IDataNode& request) {
    std::string correlationId = request.getString("correlation_id", "");
    std::string action = request.getString("action", "");

    auto response = std::make_unique<grove::JsonDataNode>("response");
    response->setString("correlation_id", correlationId);

    if (action == "save_note") {
        std::string content = request.getString("content", "");
        if (content.empty()) {
            response->setString("error", "missing_content");
        } else {
            Note note;
            note.id = "note_" + std::to_string(m_notes.size());
            note.content = content;
            // Format timestamp as ISO 8601
            auto ts = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
            char buf[64];
            std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", std::gmtime(&ts));
            note.timestamp = buf;
            m_notes.push_back(note);
            m_logger->info("Note saved: {}", note.id);

            // Also publish to StorageService for persistence
            if (m_io) {
                auto saveReq = std::make_unique<grove::JsonDataNode>("save_note");
                saveReq->setString("content", content);
                m_io->publish("storage:save_note", std::move(saveReq));
            }

            response->setBool("success", true);
            response->setString("note_id", note.id);
        }
    }
    else {
        response->setString("error", "unknown_action");
    }

    m_io->publish("storage:response", std::move(response));
}

void StorageModule::handleTaskCompleted(const grove::IDataNode& data) {
    std::string taskName = data.getString("taskName", "unknown");
    // Support both "durationMinutes" and "duration" fields
    int duration = data.getInt("durationMinutes", data.getInt("duration", 0));
    bool hyperfocus = data.getBool("hyperfocus", false);

    m_logger->debug("Task completed: {} ({}min), publishing save request", taskName, duration);

    if (m_io) {
        auto request = std::make_unique<grove::JsonDataNode>("save");
        request->setString("taskName", taskName);
        request->setInt("durationMinutes", duration);
        request->setBool("hyperfocus", hyperfocus);
        m_io->publish("storage:save_session", std::move(request));
        m_pendingSaves++;
    }
}

void StorageModule::handleAppChanged(const grove::IDataNode& data) {
    std::string appName = data.getString("oldApp", "");
    int duration = data.getInt("duration", 0);
    bool productive = data.getBool("wasProductive", false);

    if (appName.empty() || duration <= 0) return;

    m_logger->debug("App usage: {} ({}s), publishing save request", appName, duration);

    if (m_io) {
        auto request = std::make_unique<grove::JsonDataNode>("save");
        request->setInt("sessionId", m_lastSessionId);
        request->setString("appName", appName);
        request->setInt("durationSeconds", duration);
        request->setBool("productive", productive);
        m_io->publish("storage:save_app_usage", std::move(request));
        m_pendingSaves++;
    }
}

void StorageModule::handleSessionSaved(const grove::IDataNode& data) {
    m_lastSessionId = data.getInt("sessionId", 0);
    m_pendingSaves--;
    m_totalSaved++;
    m_logger->debug("Session saved: id={}", m_lastSessionId);
}

void StorageModule::handleStorageError(const grove::IDataNode& data) {
    std::string message = data.getString("message", "Unknown error");
    m_pendingSaves--;
    m_logger->error("Storage error: {}", message);
}

std::unique_ptr<grove::IDataNode> StorageModule::getHealthStatus() {
    auto status = std::make_unique<grove::JsonDataNode>("status");
    status->setString("status", "running");
    status->setInt("lastSessionId", m_lastSessionId);
    status->setInt("pendingSaves", m_pendingSaves);
    status->setInt("totalSaved", m_totalSaved);
    return status;
}

void StorageModule::shutdown() {
    m_logger->info("StorageModule arrete. Total saved: {}", m_totalSaved);
}

std::unique_ptr<grove::IDataNode> StorageModule::getState() {
    auto state = std::make_unique<grove::JsonDataNode>("state");
    state->setInt("lastSessionId", m_lastSessionId);
    state->setInt("totalSaved", m_totalSaved);
    return state;
}

void StorageModule::setState(const grove::IDataNode& state) {
    m_lastSessionId = state.getInt("lastSessionId", 0);
    m_totalSaved = state.getInt("totalSaved", 0);
    m_logger->info("Etat restore: lastSession={}, saved={}", m_lastSessionId, m_totalSaved);
}

} // namespace celuna

#ifndef CELUNA_TEST_BUILD
extern "C" {

grove::IModule* createModule() {
    return new celuna::StorageModule();
}

void destroyModule(grove::IModule* module) {
    delete module;
}

}
#endif
