/**
 * @file mcp_tool.h
 * @brief Tool definitions and helper functions for MCP
 * 
 * This file provides tool-related functionality and abstractions for the MCP protocol.
 */

#ifndef MCP_TOOL_H
#define MCP_TOOL_H

#include "mcp_message.h"
#include <functional>
#include <string>
#include <vector>
#include <map>
#include <memory>

namespace mcp {

// Tool handler function type
using tool_handler = std::function<json(const json&)>;

// MCP Tool definition
struct tool {
    std::string name;
    std::string description;
    json parameters_schema;
    
    // Convert to JSON for API documentation
    json to_json() const {
        return {
            {"name", name},
            {"description", description},
            {"parameters", parameters_schema}
        };
    }
};

/**
 * @class tool_registry
 * @brief Registry for MCP tools
 * 
 * The tool_registry class provides a centralized registry for tools that can
 * be used by agents and clients.
 */
class tool_registry {
public:
    /**
     * @brief Get the singleton instance
     * @return Reference to the singleton registry
     */
    static tool_registry& instance() {
        static tool_registry instance;
        return instance;
    }
    
    /**
     * @brief Register a tool
     * @param tool The tool to register
     * @param handler The function to call when the tool is invoked
     */
    void register_tool(const tool& tool, tool_handler handler);
    
    /**
     * @brief Unregister a tool
     * @param tool_name The name of the tool to unregister
     * @return True if the tool was found and unregistered
     */
    bool unregister_tool(const std::string& tool_name);
    
    /**
     * @brief Get a tool by name
     * @param tool_name The name of the tool
     * @return A pair containing the tool definition and handler, or nullptr if not found
     */
    std::pair<tool, tool_handler>* get_tool(const std::string& tool_name);
    
    /**
     * @brief Get all registered tools
     * @return A vector of all registered tools
     */
    std::vector<tool> get_all_tools() const;
    
    /**
     * @brief Call a tool
     * @param tool_name The name of the tool to call
     * @param parameters The parameters to pass to the tool
     * @return The result of the tool call
     * @throws mcp_exception if the tool doesn't exist or execution fails
     */
    json call_tool(const std::string& tool_name, const json& parameters);
    
private:
    // Private constructor for singleton
    tool_registry() {}
    
    // Mapping of tool names to their definitions and handlers
    std::map<std::string, std::pair<tool, tool_handler>> tools_;
    
    // Mutex for thread safety
    mutable std::mutex mutex_;
};

/**
 * @class tool_builder
 * @brief Utility class for building tools with a fluent API
 * 
 * The tool_builder class provides a simple way to create tools with
 * a fluent (chain-based) API.
 */
class tool_builder {
public:
    /**
     * @brief Constructor
     * @param name The name of the tool
     */
    explicit tool_builder(const std::string& name);
    
    /**
     * @brief Set the tool description
     * @param description The description
     * @return Reference to this builder
     */
    tool_builder& with_description(const std::string& description);
    
    /**
     * @brief Add a string parameter
     * @param name The parameter name
     * @param description The parameter description
     * @param required Whether the parameter is required
     * @return Reference to this builder
     */
    tool_builder& with_string_param(const std::string& name, 
                                   const std::string& description, 
                                   bool required = true);
    
    /**
     * @brief Add a number parameter
     * @param name The parameter name
     * @param description The parameter description
     * @param required Whether the parameter is required
     * @return Reference to this builder
     */
    tool_builder& with_number_param(const std::string& name, 
                                   const std::string& description, 
                                   bool required = true);
    
    /**
     * @brief Add a boolean parameter
     * @param name The parameter name
     * @param description The parameter description
     * @param required Whether the parameter is required
     * @return Reference to this builder
     */
    tool_builder& with_boolean_param(const std::string& name, 
                                    const std::string& description, 
                                    bool required = true);
    
    /**
     * @brief Add an array parameter
     * @param name The parameter name
     * @param description The parameter description
     * @param item_type The type of the array items ("string", "number", "object", etc.)
     * @param required Whether the parameter is required
     * @return Reference to this builder
     */
    tool_builder& with_array_param(const std::string& name, 
                                  const std::string& description,
                                  const std::string& item_type,
                                  bool required = true);
    
    /**
     * @brief Add an object parameter
     * @param name The parameter name
     * @param description The parameter description
     * @param properties JSON schema for the object properties
     * @param required Whether the parameter is required
     * @return Reference to this builder
     */
    tool_builder& with_object_param(const std::string& name, 
                                   const std::string& description,
                                   const json& properties,
                                   bool required = true);
    
    /**
     * @brief Build the tool
     * @return The constructed tool
     */
    tool build() const;
    
private:
    std::string name_;
    std::string description_;
    json parameters_;
    std::vector<std::string> required_params_;
    
    // Helper to add a parameter of any type
    tool_builder& add_param(const std::string& name, 
                           const std::string& description, 
                           const std::string& type, 
                           bool required);
};

/**
 * @brief Create a simple tool with a function-based approach
 * @param name Tool name
 * @param description Tool description
 * @param handler Function to handle tool invocations
 * @param parameter_definitions A vector of parameter definitions as {name, description, type, required}
 * @return The created tool
 */
inline tool create_tool(
    const std::string& name,
    const std::string& description,
    const std::vector<std::tuple<std::string, std::string, std::string, bool>>& parameter_definitions) {
    
    tool_builder builder(name);
    builder.with_description(description);
    
    for (const auto& [param_name, param_desc, param_type, required] : parameter_definitions) {
        if (param_type == "string") {
            builder.with_string_param(param_name, param_desc, required);
        } else if (param_type == "number") {
            builder.with_number_param(param_name, param_desc, required);
        } else if (param_type == "boolean") {
            builder.with_boolean_param(param_name, param_desc, required);
        } else if (param_type == "array") {
            builder.with_array_param(param_name, param_desc, "string", required);
        } else if (param_type == "object") {
            builder.with_object_param(param_name, param_desc, json::object(), required);
        }
    }
    
    return builder.build();
}

} // namespace mcp

#endif // MCP_TOOL_H