#include "InternalTools.hpp"
#include <spdlog/sinks/stdout_color_sinks.h>

namespace celuna {

InternalTools::InternalTools(grove::IIO* io) : m_io(io) {
    m_logger = spdlog::get("InternalTools");
    if (!m_logger) {
        m_logger = spdlog::stdout_color_mt("InternalTools");
    }

    m_bridge = std::make_unique<IOBridge>(io);
    m_bridge->subscribeToResponses();

    registerTools();

    m_logger->info("InternalTools initialized with {} tools", m_tools.size());
}

void InternalTools::registerTools() {
    // ========================================================================
    // SCHEDULER TOOLS
    // ========================================================================

    m_tools.push_back({
        "get_current_task",
        "Get the task currently being worked on. Returns task name, duration, and status.",
        {
            {"type", "object"},
            {"properties", json::object()},
            {"required", json::array()}
        },
        [this](const json& input) { return getCurrentTask(input); }
    });

    m_tools.push_back({
        "list_tasks",
        "List all planned tasks for today. Returns task names, estimated durations, and completion status.",
        {
            {"type", "object"},
            {"properties", {
                {"include_completed", {
                    {"type", "boolean"},
                    {"description", "Whether to include completed tasks"},
                    {"default", false}
                }}
            }},
            {"required", json::array()}
        },
        [this](const json& input) { return listTasks(input); }
    });

    m_tools.push_back({
        "start_task",
        "Start working on a specific task by its ID or name.",
        {
            {"type", "object"},
            {"properties", {
                {"task_id", {
                    {"type", "string"},
                    {"description", "Task ID or name to start"}
                }}
            }},
            {"required", {"task_id"}}
        },
        [this](const json& input) { return startTask(input); }
    });

    m_tools.push_back({
        "complete_task",
        "Mark the current task or a specific task as completed.",
        {
            {"type", "object"},
            {"properties", {
                {"task_id", {
                    {"type", "string"},
                    {"description", "Task ID to complete. If not provided, completes current task."}
                }}
            }},
            {"required", json::array()}
        },
        [this](const json& input) { return completeTask(input); }
    });

    m_tools.push_back({
        "start_break",
        "Start a break period. The user will be reminded when break is over.",
        {
            {"type", "object"},
            {"properties", {
                {"duration_minutes", {
                    {"type", "integer"},
                    {"description", "Break duration in minutes"},
                    {"default", 10}
                }},
                {"reason", {
                    {"type", "string"},
                    {"description", "Reason for break (coffee, stretch, etc.)"}
                }}
            }},
            {"required", json::array()}
        },
        [this](const json& input) { return startBreak(input); }
    });

    // ========================================================================
    // MONITORING TOOLS
    // ========================================================================

    m_tools.push_back({
        "get_focus_stats",
        "Get focus statistics: time spent on productive vs distracting apps, current session duration.",
        {
            {"type", "object"},
            {"properties", {
                {"period", {
                    {"type", "string"},
                    {"enum", {"today", "week", "month"}},
                    {"description", "Time period for stats"},
                    {"default", "today"}
                }}
            }},
            {"required", json::array()}
        },
        [this](const json& input) { return getFocusStats(input); }
    });

    m_tools.push_back({
        "get_current_app",
        "Get the currently active application name and window title.",
        {
            {"type", "object"},
            {"properties", json::object()},
            {"required", json::array()}
        },
        [this](const json& input) { return getCurrentApp(input); }
    });

    // ========================================================================
    // STORAGE TOOLS
    // ========================================================================

    m_tools.push_back({
        "save_note",
        "Save a note or reminder for the user. Notes are searchable and timestamped.",
        {
            {"type", "object"},
            {"properties", {
                {"content", {
                    {"type", "string"},
                    {"description", "Note content to save"}
                }},
                {"tags", {
                    {"type", "array"},
                    {"items", {{"type", "string"}}},
                    {"description", "Optional tags for categorization"}
                }}
            }},
            {"required", {"content"}}
        },
        [this](const json& input) { return saveNote(input); }
    });

    m_tools.push_back({
        "query_notes",
        "Search through saved notes by keyword or tag.",
        {
            {"type", "object"},
            {"properties", {
                {"query", {
                    {"type", "string"},
                    {"description", "Search query"}
                }},
                {"tag", {
                    {"type", "string"},
                    {"description", "Filter by tag"}
                }},
                {"limit", {
                    {"type", "integer"},
                    {"description", "Maximum number of notes to return"},
                    {"default", 10}
                }}
            }},
            {"required", json::array()}
        },
        [this](const json& input) { return queryNotes(input); }
    });

    m_tools.push_back({
        "get_session_history",
        "Get history of work sessions with durations and focus scores.",
        {
            {"type", "object"},
            {"properties", {
                {"days", {
                    {"type", "integer"},
                    {"description", "Number of days to look back"},
                    {"default", 7}
                }}
            }},
            {"required", json::array()}
        },
        [this](const json& input) { return getSessionHistory(input); }
    });

    // ========================================================================
    // VOICE TOOLS
    // ========================================================================

    m_tools.push_back({
        "speak",
        "Make the assistant speak a message out loud using text-to-speech.",
        {
            {"type", "object"},
            {"properties", {
                {"message", {
                    {"type", "string"},
                    {"description", "Message to speak"}
                }},
                {"priority", {
                    {"type", "string"},
                    {"enum", {"low", "normal", "high"}},
                    {"description", "Speech priority"},
                    {"default", "normal"}
                }}
            }},
            {"required", {"message"}}
        },
        [this](const json& input) { return speak(input); }
    });
}

std::vector<ToolDefinition> InternalTools::getTools() const {
    return m_tools;
}

void InternalTools::processResponses() {
    if (!m_io) return;

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

        // Check if this is a response message
        if (msg.topic.find(":response") != std::string::npos && msg.data) {
            m_bridge->handleResponse(msg.topic, *msg.data);
        }
    }
}

// ============================================================================
// TOOL IMPLEMENTATIONS
// ============================================================================

json InternalTools::getCurrentTask(const json& input) {
    auto response = m_bridge->request("scheduler:query", {
        {"action", "get_current_task"}
    });

    if (response.contains("error")) {
        return response;
    }

    return {
        {"task_id", response.value("task_id", "")},
        {"task_name", response.value("task_name", "No active task")},
        {"duration_minutes", response.value("duration_minutes", 0)},
        {"started_at", response.value("started_at", "")}
    };
}

json InternalTools::listTasks(const json& input) {
    bool includeCompleted = input.value("include_completed", false);

    auto response = m_bridge->request("scheduler:query", {
        {"action", "list_tasks"},
        {"include_completed", includeCompleted}
    });

    return response;
}

json InternalTools::startTask(const json& input) {
    std::string taskId = input.value("task_id", "");
    if (taskId.empty()) {
        return {{"error", "missing_parameter"}, {"message", "task_id is required"}};
    }

    auto response = m_bridge->request("scheduler:command", {
        {"action", "start_task"},
        {"task_id", taskId}
    });

    return response;
}

json InternalTools::completeTask(const json& input) {
    std::string taskId = input.value("task_id", "");

    auto response = m_bridge->request("scheduler:command", {
        {"action", "complete_task"},
        {"task_id", taskId}  // Empty = complete current task
    });

    return response;
}

json InternalTools::startBreak(const json& input) {
    int duration = input.value("duration_minutes", 10);
    std::string reason = input.value("reason", "break");

    auto response = m_bridge->request("scheduler:command", {
        {"action", "start_break"},
        {"duration_minutes", duration},
        {"reason", reason}
    });

    return {
        {"success", true},
        {"message", "Break started for " + std::to_string(duration) + " minutes"},
        {"reason", reason}
    };
}

json InternalTools::getFocusStats(const json& input) {
    std::string period = input.value("period", "today");

    auto response = m_bridge->request("monitoring:query", {
        {"action", "get_focus_stats"},
        {"period", period}
    });

    return response;
}

json InternalTools::getCurrentApp(const json& input) {
    auto response = m_bridge->request("monitoring:query", {
        {"action", "get_current_app"}
    });

    return response;
}

json InternalTools::saveNote(const json& input) {
    std::string content = input.value("content", "");
    if (content.empty()) {
        return {{"error", "missing_parameter"}, {"message", "content is required"}};
    }

    json tags = input.value("tags", json::array());

    auto response = m_bridge->request("storage:command", {
        {"action", "save_note"},
        {"content", content},
        {"tags", tags}
    });

    return {
        {"success", true},
        {"message", "Note saved"},
        {"note_id", response.value("note_id", "")}
    };
}

json InternalTools::queryNotes(const json& input) {
    std::string query = input.value("query", "");
    std::string tag = input.value("tag", "");
    int limit = input.value("limit", 10);

    auto response = m_bridge->request("storage:query", {
        {"action", "query_notes"},
        {"query", query},
        {"tag", tag},
        {"limit", limit}
    });

    return response;
}

json InternalTools::getSessionHistory(const json& input) {
    int days = input.value("days", 7);

    auto response = m_bridge->request("storage:query", {
        {"action", "get_session_history"},
        {"days", days}
    });

    return response;
}

json InternalTools::speak(const json& input) {
    std::string message = input.value("message", "");
    if (message.empty()) {
        return {{"error", "missing_parameter"}, {"message", "message is required"}};
    }

    std::string priority = input.value("priority", "normal");

    // For speak, we don't wait for response - it's fire and forget
    auto requestNode = std::make_unique<grove::JsonDataNode>("request");
    requestNode->setString("action", "speak");
    requestNode->setString("text", message);
    requestNode->setString("priority", priority);

    m_io->publish("voice:command", std::move(requestNode));

    return {
        {"success", true},
        {"message", "Speech queued"}
    };
}

} // namespace celuna
