/**
 * @file mcp_tool.cpp
 * @brief Implementation of the MCP tools
 * 
 * This file implements the tool-related functionality for the MCP protocol.
 * Follows the 2024-11-05 basic protocol specification.
 */

#include "mcp_tool.h"
#include <random>
#include <sstream>

namespace mcp {

// Implementation for tool_registry
void tool_registry::register_tool(const tool& tool, tool_handler handler) {
    std::lock_guard<std::mutex> lock(mutex_);
    tools_[tool.name] = std::make_pair(tool, handler);
}

bool tool_registry::unregister_tool(const std::string& tool_name) {
    std::lock_guard<std::mutex> lock(mutex_);
    return tools_.erase(tool_name) > 0;
}

std::pair<tool, tool_handler>* tool_registry::get_tool(const std::string& tool_name) {
    std::lock_guard<std::mutex> lock(mutex_);
    auto it = tools_.find(tool_name);
    if (it != tools_.end()) {
        return &(it->second);
    }
    return nullptr;
}

std::vector<tool> tool_registry::get_all_tools() const {
    std::lock_guard<std::mutex> lock(mutex_);
    std::vector<tool> result;
    for (const auto& [name, tool_pair] : tools_) {
        result.push_back(tool_pair.first);
    }
    return result;
}

json tool_registry::call_tool(const std::string& tool_name, const json& parameters) {
    std::lock_guard<std::mutex> lock(mutex_);
    
    auto it = tools_.find(tool_name);
    if (it == tools_.end()) {
        throw mcp_exception(error_code::method_not_found, "Tool not found: " + tool_name);
    }
    
    try {
        return it->second.second(parameters);
    } catch (const std::exception& e) {
        throw mcp_exception(error_code::internal_error,
                        "Tool execution failed: " + std::string(e.what()));
    }
}

// Implementation for tool_builder
tool_builder::tool_builder(const std::string& name)
    : name_(name) {
}

tool_builder& tool_builder::with_description(const std::string& description) {
    description_ = description;
    return *this;
}

tool_builder& tool_builder::add_param(const std::string& name, 
                                     const std::string& description, 
                                     const std::string& type, 
                                     bool required) {
    json param = {
        {"type", type},
        {"description", description}
    };
    
    parameters_["properties"][name] = param;
    
    if (required) {
        required_params_.push_back(name);
    }
    
    return *this;
}

tool_builder& tool_builder::with_string_param(const std::string& name, 
                                             const std::string& description, 
                                             bool required) {
    return add_param(name, description, "string", required);
}

tool_builder& tool_builder::with_number_param(const std::string& name, 
                                             const std::string& description, 
                                             bool required) {
    return add_param(name, description, "number", required);
}

tool_builder& tool_builder::with_boolean_param(const std::string& name, 
                                              const std::string& description, 
                                              bool required) {
    return add_param(name, description, "boolean", required);
}

tool_builder& tool_builder::with_array_param(const std::string& name, 
                                            const std::string& description,
                                            const std::string& item_type,
                                            bool required) {
    json param = {
        {"type", "array"},
        {"description", description},
        {"items", {
            {"type", item_type}
        }}
    };
    
    parameters_["properties"][name] = param;
    
    if (required) {
        required_params_.push_back(name);
    }
    
    return *this;
}

tool_builder& tool_builder::with_object_param(const std::string& name, 
                                             const std::string& description,
                                             const json& properties,
                                             bool required) {
    json param = {
        {"type", "object"},
        {"description", description},
        {"properties", properties}
    };
    
    parameters_["properties"][name] = param;
    
    if (required) {
        required_params_.push_back(name);
    }
    
    return *this;
}

tool tool_builder::build() const {
    tool t;
    t.name = name_;
    t.description = description_;
    
    // Create the parameters schema
    json schema = parameters_;
    schema["type"] = "object";
    
    if (!required_params_.empty()) {
        schema["required"] = required_params_;
    }
    
    t.parameters_schema = schema;
    
    return t;
}

} // namespace mcp