#pragma once

#include <nlohmann/json.hpp>
#include <string>
#include <vector>
#include <memory>

namespace celuna {

using json = nlohmann::json;

/**
 * @brief Represents a tool call requested by the LLM
 */
struct ToolCall {
    std::string id;      // Unique identifier for this call
    std::string name;    // Tool name
    json input;          // Arguments passed to the tool
};

/**
 * @brief Result of executing a tool
 */
struct ToolResult {
    std::string tool_call_id;  // Reference to the ToolCall.id
    std::string content;       // Result content (usually JSON string)
    bool is_error = false;     // Whether this is an error result
};

/**
 * @brief Response from an LLM provider
 */
struct LLMResponse {
    std::string text;                    // Text response (if any)
    std::vector<ToolCall> tool_calls;    // Tool calls requested
    bool is_end_turn = false;            // True if this is a final response
    int input_tokens = 0;                // Tokens used for input
    int output_tokens = 0;               // Tokens generated
    std::string stop_reason;             // Why generation stopped
    std::string model;                   // Model that generated this
};

/**
 * @brief Abstract interface for LLM providers
 *
 * Implementations:
 * - ClaudeProvider: Anthropic Claude API
 * - OpenAIProvider: OpenAI GPT API
 * - OllamaProvider: Local Ollama models
 *
 * All providers support tool use for agentic workflows.
 */
class ILLMProvider {
public:
    virtual ~ILLMProvider() = default;

    /**
     * @brief Send a chat completion request
     *
     * @param systemPrompt System instructions for the assistant
     * @param messages Conversation history (role/content pairs)
     * @param tools Available tools in provider-agnostic format
     * @return LLMResponse with text and/or tool calls
     */
    virtual LLMResponse chat(const std::string& systemPrompt,
                             const json& messages,
                             const json& tools) = 0;

    /**
     * @brief Format tool results for the next request
     *
     * Different providers have different formats for returning tool results.
     * Claude uses tool_result blocks, OpenAI uses tool role messages.
     *
     * @param results Vector of tool results to format
     * @return JSON message(s) to append to conversation
     */
    virtual json formatToolResults(const std::vector<ToolResult>& results) = 0;

    /**
     * @brief Append assistant response to message history
     *
     * @param messages Message array to modify
     * @param response Response to append
     */
    virtual void appendAssistantMessage(json& messages, const LLMResponse& response) = 0;

    /**
     * @brief Get provider name for logging
     */
    virtual std::string getProviderName() const = 0;

    /**
     * @brief Set the model to use
     */
    virtual void setModel(const std::string& model) = 0;

    /**
     * @brief Set maximum tokens for response
     */
    virtual void setMaxTokens(int maxTokens) = 0;

    /**
     * @brief Get current model name
     */
    virtual std::string getModel() const = 0;
};

} // namespace celuna
