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

namespace celuna {

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

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

    // Charger la configuration
    m_hyperfocusThresholdMinutes = configNode.getInt("hyperfocusThresholdMinutes", 120);
    m_breakReminderIntervalMinutes = configNode.getInt("breakReminderIntervalMinutes", 45);
    m_breakDurationMinutes = configNode.getInt("breakDurationMinutes", 10);

    // Subscribe to topics
    if (m_io) {
        grove::SubscriptionConfig subConfig;
        m_io->subscribe("user:activity", subConfig);
        m_io->subscribe("user:task_switch", subConfig);
        m_io->subscribe("monitoring:idle_detected", subConfig);
        m_io->subscribe("monitoring:activity_resumed", subConfig);
        // Tool request handlers
        m_io->subscribe("scheduler:query", subConfig);
        m_io->subscribe("scheduler:command", subConfig);
    }

    m_logger->info("SchedulerModule configure: hyperfocus={}min, break_interval={}min",
                  m_hyperfocusThresholdMinutes, m_breakReminderIntervalMinutes);
}

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

void SchedulerModule::process(const grove::IDataNode& input) {
    m_lastActivityTime = input.getDouble("gameTime", 0.0);
    processMessages();
    float sessionMinutes = (m_lastActivityTime - m_sessionStartTime) / 60.0f;
    checkHyperfocus(m_lastActivityTime);
    checkBreakReminder(m_lastActivityTime);
    // Log periodique (toutes les 5 minutes)
    static float lastLog = 0;
    if (m_lastActivityTime - lastLog > 300.0f) {
        lastLog = m_lastActivityTime;
        m_logger->debug("Session: {:.1f}min, Focus: {}min, Tache: {}", sessionMinutes,
                       m_totalFocusMinutesToday, m_currentTaskId.empty() ? "(aucune)" : m_currentTaskId);
    }
}

void SchedulerModule::processMessages() {
    if (!m_io) return;
    while (m_io->hasMessages() > 0) {
        auto msg = m_io->pullMessage();
        if (msg.topic == "user:task_switch" && msg.data) {
            std::string taskId = msg.data->getString("taskId", "");
            if (!taskId.empty()) startTask(taskId);
        }
        else if (msg.topic == "monitoring:idle_detected" && msg.data)
            m_logger->debug("User idle, pausing session tracking");
        else if (msg.topic == "monitoring:activity_resumed" && msg.data)
            m_logger->debug("User active, resuming session tracking");
        else if (msg.topic == "scheduler:query" && msg.data)
            handleToolQuery(*msg.data);
        else if (msg.topic == "scheduler:command" && msg.data)
            handleToolCommand(*msg.data);
    }
}

void SchedulerModule::handleToolQuery(const grove::IDataNode& request) {
    auto response = std::make_unique<grove::JsonDataNode>("response");
    response->setString("correlation_id", request.getString("correlation_id", ""));
    std::string action = request.getString("action", "");

    if (action == "get_current_task") {
        Task* task = findTask(m_currentTaskId);
        response->setString("task_id", m_currentTaskId);
        response->setString("task_name", task ? task->name : (m_currentTaskId.empty() ? "Aucune tache active" : m_currentTaskId));
        float sessionMinutes = m_currentTaskId.empty() ? 0 : (m_lastActivityTime - m_sessionStartTime) / 60.0f;
        response->setInt("duration_minutes", static_cast<int>(sessionMinutes));
        // Format timestamp: calculate start time from elapsed seconds
        if (!m_currentTaskId.empty()) {
            auto now = std::chrono::system_clock::now() - std::chrono::seconds(static_cast<long long>(m_lastActivityTime - m_sessionStartTime));
            auto ts = std::chrono::system_clock::to_time_t(now);
            char buf[64];
            std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", std::gmtime(&ts));
            response->setString("started_at", buf);
        } else {
            response->setString("started_at", "");
        }
    }
    else if (action == "list_tasks") {
        bool includeCompleted = request.getBool("include_completed", false);
        // Build task list as JSON-like structure
        int count = 0;
        for (const auto& task : m_tasks) {
            if (!includeCompleted && task.completed) continue;
            auto taskNode = std::make_unique<grove::JsonDataNode>("task_" + std::to_string(count));
            taskNode->setString("id", task.id);
            taskNode->setString("name", task.name);
            taskNode->setInt("estimated_minutes", task.estimatedMinutes);
            taskNode->setInt("actual_minutes", task.actualMinutes);
            taskNode->setBool("completed", task.completed);
            response->setChild("task_" + std::to_string(count), std::move(taskNode));
            count++;
        }
        response->setInt("task_count", count);
        response->setString("current_task", m_currentTaskId);
    }
    else {
        response->setString("error", "unknown_action");
    }

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

void SchedulerModule::handleToolCommand(const grove::IDataNode& request) {
    auto response = std::make_unique<grove::JsonDataNode>("response");
    response->setString("correlation_id", request.getString("correlation_id", ""));
    std::string action = request.getString("action", "");

    if (action == "start_task") {
        std::string taskId = request.getString("task_id", "");
        if (taskId.empty())
            response->setString("error", "missing_task_id");
        else {
            startTask(taskId);
            response->setBool("success", true);
            response->setString("task_id", taskId);
        }
    }
    else if (action == "complete_task") {
        std::string taskId = request.getString("task_id", "");
        if (taskId.empty())
            completeCurrentTask();
        else {
            Task* task = findTask(taskId);
            if (task) task->completed = true;
        }
        response->setBool("success", true);
    }
    else if (action == "start_break") {
        int duration = request.getInt("duration_minutes", m_breakDurationMinutes);
        std::string reason = request.getString("reason", "break");
        m_lastBreakTime = m_lastActivityTime;
        m_logger->info("Pause demarree: {} minutes ({})", duration, reason);
        auto event = std::make_unique<grove::JsonDataNode>("break");
        event->setInt("duration", duration);
        event->setString("reason", reason);
        m_io->publish("scheduler:break_started", std::move(event));
        response->setBool("success", true);
        response->setInt("duration", duration);
    }
    else
        response->setString("error", "unknown_action");

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

void SchedulerModule::checkHyperfocus(float currentTime) {
    if (m_currentTaskId.empty()) return;
    float sessionMinutes = (currentTime - m_sessionStartTime) / 60.0f;
    if (sessionMinutes >= m_hyperfocusThresholdMinutes && !m_hyperfocusAlertSent) {
        m_hyperfocusAlertSent = true;
        m_logger->warn("HYPERFOCUS DETECTE! Session de {:.0f} minutes sur '{}'", sessionMinutes, m_currentTaskId);
        if (m_io) {
            auto event = std::make_unique<grove::JsonDataNode>("alert");
            event->setString("type", "hyperfocus");
            event->setInt("duration_minutes", static_cast<int>(sessionMinutes));
            event->setString("task", m_currentTaskId);
            m_io->publish("scheduler:hyperfocus_alert", std::move(event));
        }
    }
}

void SchedulerModule::checkBreakReminder(float currentTime) {
    float timeSinceBreak = (currentTime - m_lastBreakTime) / 60.0f;
    if (timeSinceBreak >= m_breakReminderIntervalMinutes) {
        m_lastBreakTime = currentTime;
        m_logger->info("RAPPEL: Pause de {} minutes recommandee!", m_breakDurationMinutes);
        if (m_io) {
            auto event = std::make_unique<grove::JsonDataNode>("reminder");
            event->setString("type", "break");
            event->setInt("break_duration", m_breakDurationMinutes);
            event->setInt("time_since_last_break", static_cast<int>(timeSinceBreak));
            m_io->publish("scheduler:break_reminder", std::move(event));
        }
    }
}

void SchedulerModule::startTask(const std::string& taskId) {
    if (!m_currentTaskId.empty()) completeCurrentTask();
    m_currentTaskId = taskId;
    m_sessionStartTime = m_lastActivityTime;
    m_hyperfocusAlertSent = false;
    Task* task = findTask(taskId);
    if (task) m_logger->info("Tache demarree: {} (estime: {}min)", task->name, task->estimatedMinutes);
    if (m_io) {
        auto event = std::make_unique<grove::JsonDataNode>("started");
        event->setString("taskId", taskId);
        event->setString("taskName", task ? task->name : taskId);
        m_io->publish("scheduler:task_started", std::move(event));
    }
}

void SchedulerModule::completeCurrentTask() {
    if (m_currentTaskId.empty()) return;
    Task* task = findTask(m_currentTaskId);
    float sessionMinutes = (m_lastActivityTime - m_sessionStartTime) / 60.0f;
    if (task) {
        task->actualMinutes = static_cast<int>(sessionMinutes);
        task->completed = true;
        m_totalFocusMinutesToday += task->actualMinutes;
        m_logger->info("Tache terminee: {} (reel: {}min vs estime: {}min)", task->name, task->actualMinutes, task->estimatedMinutes);
    }
    if (m_io) {
        auto event = std::make_unique<grove::JsonDataNode>("completed");
        event->setString("taskId", m_currentTaskId);
        event->setString("taskName", task ? task->name : m_currentTaskId);
        event->setInt("duration", static_cast<int>(sessionMinutes));
        event->setBool("hyperfocus", m_hyperfocusAlertSent);
        m_io->publish("scheduler:task_completed", std::move(event));
    }
    m_currentTaskId.clear();
}

SchedulerModule::Task* SchedulerModule::findTask(const std::string& taskId) {
    for (auto& task : m_tasks) {
        if (task.id == taskId) return &task;
    }
    return nullptr;
}

std::unique_ptr<grove::IDataNode> SchedulerModule::getHealthStatus() {
    auto status = std::make_unique<grove::JsonDataNode>("status");
    status->setString("status", "running");
    status->setInt("taskCount", m_tasks.size());
    status->setString("currentTask", m_currentTaskId);
    status->setInt("totalFocusMinutesToday", m_totalFocusMinutesToday);
    status->setBool("hyperfocusAlertSent", m_hyperfocusAlertSent);
    return status;
}

void SchedulerModule::shutdown() {
    if (!m_currentTaskId.empty()) completeCurrentTask();
    m_logger->info("SchedulerModule arrete. Focus total: {}min", m_totalFocusMinutesToday);
}

std::unique_ptr<grove::IDataNode> SchedulerModule::getState() {
    auto state = std::make_unique<grove::JsonDataNode>("state");
    state->setString("currentTaskId", m_currentTaskId);
    state->setDouble("sessionStartTime", m_sessionStartTime);
    state->setDouble("lastBreakTime", m_lastBreakTime);
    state->setDouble("lastActivityTime", m_lastActivityTime);
    state->setBool("hyperfocusAlertSent", m_hyperfocusAlertSent);
    state->setInt("totalFocusMinutesToday", m_totalFocusMinutesToday);
    state->setInt("taskCount", m_tasks.size());
    m_logger->debug("Etat sauvegarde: {} taches, focus={}min", m_tasks.size(), m_totalFocusMinutesToday);
    return state;
}

void SchedulerModule::setState(const grove::IDataNode& state) {
    m_currentTaskId = state.getString("currentTaskId", "");
    m_sessionStartTime = state.getDouble("sessionStartTime", 0.0);
    m_lastBreakTime = state.getDouble("lastBreakTime", 0.0);
    m_lastActivityTime = state.getDouble("lastActivityTime", 0.0);
    m_hyperfocusAlertSent = state.getBool("hyperfocusAlertSent", false);
    m_totalFocusMinutesToday = state.getInt("totalFocusMinutesToday", 0);
    m_logger->info("Etat restaure: tache='{}', focus={}min", m_currentTaskId.empty() ? "(aucune)" : m_currentTaskId, m_totalFocusMinutesToday);
}

} // namespace celuna

#ifndef CELUNA_TEST_BUILD
extern "C" {

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

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

}
#endif
