/**
 * @file MCPTypesTests.cpp
 * @brief Integration tests for MCP Types (15 TI)
 */

#include <catch2/catch_test_macros.hpp>
#include "shared/mcp/MCPTypes.hpp"

using namespace celuna::mcp;
using json = nlohmann::json;

// ============================================================================
// TI_TYPES_001: MCPTool toJson
// ============================================================================

TEST_CASE("TI_TYPES_001_MCPToolToJson", "[mcp][types]") {
    MCPTool tool;
    tool.name = "read_file";
    tool.description = "Read a file from the filesystem";
    tool.inputSchema = {
        {"type", "object"},
        {"properties", {
            {"path", {{"type", "string"}}}
        }},
        {"required", json::array({"path"})}
    };

    json j = tool.toJson();

    REQUIRE(j["name"] == "read_file");
    REQUIRE(j["description"] == "Read a file from the filesystem");
    REQUIRE(j["inputSchema"]["type"] == "object");
    REQUIRE(j["inputSchema"]["properties"]["path"]["type"] == "string");
}

// ============================================================================
// TI_TYPES_002: MCPTool fromJson
// ============================================================================

TEST_CASE("TI_TYPES_002_MCPToolFromJson", "[mcp][types]") {
    json j = {
        {"name", "write_file"},
        {"description", "Write content to a file"},
        {"inputSchema", {
            {"type", "object"},
            {"properties", {
                {"path", {{"type", "string"}}},
                {"content", {{"type", "string"}}}
            }}
        }}
    };

    auto tool = MCPTool::fromJson(j);

    REQUIRE(tool.name == "write_file");
    REQUIRE(tool.description == "Write content to a file");
    REQUIRE(tool.inputSchema["type"] == "object");
}

// ============================================================================
// TI_TYPES_003: MCPTool fromJson with missing fields
// ============================================================================

TEST_CASE("TI_TYPES_003_MCPToolFromJsonMissingFields", "[mcp][types]") {
    json j = {{"name", "minimal_tool"}};

    auto tool = MCPTool::fromJson(j);

    REQUIRE(tool.name == "minimal_tool");
    REQUIRE(tool.description == "");
    REQUIRE(tool.inputSchema.is_object());
}

// ============================================================================
// TI_TYPES_004: MCPResource fromJson
// ============================================================================

TEST_CASE("TI_TYPES_004_MCPResourceFromJson", "[mcp][types]") {
    json j = {
        {"uri", "file:///home/user/doc.txt"},
        {"name", "Document"},
        {"description", "A text document"},
        {"mimeType", "text/plain"}
    };

    auto resource = MCPResource::fromJson(j);

    REQUIRE(resource.uri == "file:///home/user/doc.txt");
    REQUIRE(resource.name == "Document");
    REQUIRE(resource.description == "A text document");
    REQUIRE(resource.mimeType == "text/plain");
}

// ============================================================================
// TI_TYPES_005: MCPToolResult toJson
// ============================================================================

TEST_CASE("TI_TYPES_005_MCPToolResultToJson", "[mcp][types]") {
    MCPToolResult result;
    result.content = {
        {{"type", "text"}, {"text", "File contents here"}},
        {{"type", "text"}, {"text", "More content"}}
    };
    result.isError = false;

    json j = result.toJson();

    REQUIRE(j["content"].size() == 2);
    REQUIRE(j["content"][0]["type"] == "text");
    REQUIRE(j["isError"] == false);
}

// ============================================================================
// TI_TYPES_006: MCPCapabilities fromJson
// ============================================================================

TEST_CASE("TI_TYPES_006_MCPCapabilitiesFromJson", "[mcp][types]") {
    json j = {
        {"tools", json::object()},
        {"resources", {{"subscribe", true}}},
        {"prompts", json::object()}
    };

    auto caps = MCPCapabilities::fromJson(j);

    REQUIRE(caps.hasTools == true);
    REQUIRE(caps.hasResources == true);
    REQUIRE(caps.hasPrompts == true);
}

// ============================================================================
// TI_TYPES_007: MCPCapabilities empty
// ============================================================================

TEST_CASE("TI_TYPES_007_MCPCapabilitiesEmpty", "[mcp][types]") {
    json j = json::object();

    auto caps = MCPCapabilities::fromJson(j);

    REQUIRE(caps.hasTools == false);
    REQUIRE(caps.hasResources == false);
    REQUIRE(caps.hasPrompts == false);
}

// ============================================================================
// TI_TYPES_008: MCPServerInfo fromJson
// ============================================================================

TEST_CASE("TI_TYPES_008_MCPServerInfoFromJson", "[mcp][types]") {
    json j = {
        {"name", "filesystem-server"},
        {"version", "1.2.3"},
        {"capabilities", {
            {"tools", json::object()}
        }}
    };

    auto info = MCPServerInfo::fromJson(j);

    REQUIRE(info.name == "filesystem-server");
    REQUIRE(info.version == "1.2.3");
    REQUIRE(info.capabilities.hasTools == true);
}

// ============================================================================
// TI_TYPES_009: JsonRpcRequest toJson
// ============================================================================

TEST_CASE("TI_TYPES_009_JsonRpcRequestToJson", "[mcp][types]") {
    JsonRpcRequest request;
    request.id = 42;
    request.method = "tools/call";
    request.params = {{"name", "read_file"}, {"arguments", {{"path", "/tmp/test"}}}};

    json j = request.toJson();

    REQUIRE(j["jsonrpc"] == "2.0");
    REQUIRE(j["id"] == 42);
    REQUIRE(j["method"] == "tools/call");
    REQUIRE(j["params"]["name"] == "read_file");
}

// ============================================================================
// TI_TYPES_010: JsonRpcResponse fromJson
// ============================================================================

TEST_CASE("TI_TYPES_010_JsonRpcResponseFromJson", "[mcp][types]") {
    json j = {
        {"jsonrpc", "2.0"},
        {"id", 42},
        {"result", {{"tools", json::array()}}}
    };

    auto response = JsonRpcResponse::fromJson(j);

    REQUIRE(response.jsonrpc == "2.0");
    REQUIRE(response.id == 42);
    REQUIRE(response.result.has_value());
    REQUIRE(response.result.value()["tools"].is_array());
}

// ============================================================================
// TI_TYPES_011: JsonRpcResponse isError
// ============================================================================

TEST_CASE("TI_TYPES_011_JsonRpcResponseIsError", "[mcp][types]") {
    json errorJson = {
        {"jsonrpc", "2.0"},
        {"id", 1},
        {"error", {{"code", -32600}, {"message", "Invalid Request"}}}
    };

    auto response = JsonRpcResponse::fromJson(errorJson);

    REQUIRE(response.isError() == true);
    REQUIRE(response.error.has_value());
    REQUIRE(response.error.value()["code"] == -32600);
    REQUIRE(response.error.value()["message"] == "Invalid Request");
}

// ============================================================================
// TI_TYPES_012: MCPServerConfig fromJson
// ============================================================================

TEST_CASE("TI_TYPES_012_MCPServerConfigFromJson", "[mcp][types]") {
    json j = {
        {"command", "mcp-server-filesystem"},
        {"args", json::array({"--root", "/home"})},
        {"env", {{"DEBUG", "true"}}},
        {"enabled", true}
    };

    auto config = MCPServerConfig::fromJson("filesystem", j);

    REQUIRE(config.name == "filesystem");
    REQUIRE(config.command == "mcp-server-filesystem");
    REQUIRE(config.args.size() == 2);
    REQUIRE(config.args[0] == "--root");
    REQUIRE(config.args[1] == "/home");
    REQUIRE(config.env["DEBUG"] == "true");
    REQUIRE(config.enabled == true);
}

// ============================================================================
// TI_TYPES_013: MCPServerConfig env expansion
// ============================================================================

TEST_CASE("TI_TYPES_013_MCPServerConfigEnvExpansion", "[mcp][types]") {
    json j = {
        {"command", "mcp-server"},
        {"env", {{"API_KEY", "${MY_API_KEY}"}}}
    };

    auto config = MCPServerConfig::fromJson("test", j);

    // Note: Actual env expansion happens in MCPClient, not in fromJson
    // This test verifies the raw value is stored
    REQUIRE(config.env["API_KEY"] == "${MY_API_KEY}");
}

// ============================================================================
// TI_TYPES_014: MCPServerConfig disabled
// ============================================================================

TEST_CASE("TI_TYPES_014_MCPServerConfigDisabled", "[mcp][types]") {
    json j = {
        {"command", "some-server"},
        {"enabled", false}
    };

    auto config = MCPServerConfig::fromJson("disabled_server", j);

    REQUIRE(config.enabled == false);
}

// ============================================================================
// TI_TYPES_015: JsonRpcRequest ID increment
// ============================================================================

TEST_CASE("TI_TYPES_015_JsonRpcRequestIdIncrement", "[mcp][types]") {
    JsonRpcRequest req1;
    req1.id = 1;
    req1.method = "test";

    JsonRpcRequest req2;
    req2.id = 2;
    req2.method = "test";

    // IDs should be different
    REQUIRE(req1.id != req2.id);

    // Both should serialize correctly
    json j1 = req1.toJson();
    json j2 = req2.toJson();

    REQUIRE(j1["id"] == 1);
    REQUIRE(j2["id"] == 2);
}
