#include <iostream>
#include <vector>
#include "../lsp-server/src/protocol/protocol.hpp"
#include "../lsp-server/src/protocol/transform/facade.hpp"

using namespace lsp::protocol;
using namespace lsp;

template<typename T>
void print_json(const string& name, const T& obj)
{
    if (auto result = glz::write_json(obj); result)
    {
        std::cout << name << " = " << *result << std::endl;
    } else
    {
        std::cerr << "Error: " << result.error() << "\n";
    }
}

void test_basic_conversion()
{
    std::cout << "\n=== Testing Basic Conversion ===" << std::endl;

    // 测试 struct 转换
    RequestMessage msg;
    msg.method = "textDocument/completion";
    msg.id = 42;

    // Struct -> LSPAny
    LSPAny any = transform::LSPAny(msg);
    std::string json;
    auto ce = glz::write_json(any, json);
    if(ce)
        std::cout << "Error" << std::endl;
    std::cout << "Message as JSON: " << json << std::endl;

    // LSPAny -> Struct
    RequestMessage restored = transform::As<RequestMessage>(any);
    std::cout << "Restored method: " << restored.method << std::endl;
    std::cout << "id = ";
    std::visit([](const auto& value)
    {
        std::cout << value;
    }, restored.id);
    std::cout << std::endl;
}

void test_vector_conversion()
{
    std::cout << "\n=== Testing Vector Conversion ===" << std::endl;

    std::vector<Position> positions = {
        {10, 5},
        {20, 15},
        {30, 25}
    };

    // Vector -> LSPAny
    LSPAny any = transform::LSPAny(positions);

    std::string json;
    auto ce = glz::write_json(any, json);
    std::cout << "Vector as JSON: " << json << std::endl;

    // LSPAny -> Vector
    auto restored = transform::As<std::vector<Position>>(any);
    std::cout << "Restored " << restored.size() << " positions" << std::endl;
}

void test_json_string()
{
    std::cout << "\n=== Test json_string ===" << std::endl;

    string json = R"({"jsonrpc":"2.0","id":1,"method":"initialize","params":{"processId":null,"rootUri":"file:///tmp","workDoneToken":"abc"}})";
    RequestMessage request;
    auto ret = glz::read_json(request, json);
    std::cout << "jsonrpc = " << request.jsonrpc << std::endl;
    std::cout << "method = " << request.method << std::endl;
    std::cout << "id = ";
    std::visit([](const auto& value)
    {
        std::cout << value;
    }, request.id);
    std::cout << std::endl;

    auto result = glz::write_json(request.params);
    std::cout << *result << std::endl;
    InitializeParams params;
    // std::string buffer = R"({"workDoneToken":123,"processId":"id","clientInfo":{"name":"VSCode","version":"1.0.0"},"rootPath":"456","initializationOptions":"options","trace":"messages"})";
    auto r2= glz::read_json(params, *result);
    if (params.processId.has_value())
        std::cout << "processId = " << params.processId.value() << "\n";
    else
        std::cout << "processId = null\n";
    std::cout << "rootUri = " << params.rootUri.value() << std::endl;

    std::cout << std::endl;
}

void test_basic_types()
{
    std::cout << "\n=== Test basic_types.hpp ===" << std::endl;
    Range range =
    {
        .start = {1, 3},
        .end = {2, 4}
    };

    DocumentFilter df = {
        .language = "en",
        .scheme = "scheme",
        .pattern = "pattern",
    };

    AnnotatedTextEdit ate;
    ate.range = {.start = {1, 3}, .end = {2, 4}};
    ate.newText = "text_edit";
    ate.annotationId = "id";

    Location location =
    {
        .uri = "location_uri",
        .range = {.start = {1, 3}, .end = {2, 4}}
    };

    Command command1 =
    {
        .title = "command_title",
        .command = "command_command",
    };
    Command command2 =
    {
        .title = "command_title",
        .command = "command_command",
        .arguments = "any_string"
    };
    Command command3 =
    {
        .title = "command_title",
        .command = "command_command",
        .arguments = 123
    };
    std::vector<LSPAny> array = {
        1.0,      // decimal
        string("two"),
        3.0,      // decimal
        true,
        nullptr
    };
    LSPAny array_val = array;
    LSPObject object = {
        {"name", string("test object")},
        {"count", 42.0},  // decimal
        {"active", boolean(true)},
        {"data", array_val},
        {"metadata", nullptr}
    };
    Command command4 =
    {
        .title = "command_title",
        .command = "command_command",
        .arguments = object
    };

    MarkdownClientCapabilities mkcp =
    {
        .parser = "parse",
        .allowedTags = std::vector<string>{"h1", "h2", "p", "code", "pre"}
    };
    std::cout << "Test....basic_types" << std::endl;
    print_json("Range", range);
    print_json("DocumentFilter", df);
    print_json("AnnotatedTextEdit", ate);
    print_json("Location", location);
    print_json("Command1", command1);
    print_json("Command2", command2);
    print_json("Command3", command3);
    print_json("Command4", command4);
    print_json("MarkdownClientCapabilities", mkcp);
    std::cout << std::endl;
}

void test_capabilities()
{
    std::cout << "\n=== Test capabilities.hpp ===" << std::endl;
    InitializeParams ip;
    ip.workDoneToken = 123;
    ip.processId = std::nullopt;
    ip.clientInfo = InitializeParams::ClientInfo{"VSCode", "1.0.0"};
    ip.rootPath = "456";
    ip.initializationOptions = "options";
    ip.trace = TraceValueLiterals::Messages;

    std::cout << "Test....capabilities" << std::endl;
    print_json("InitializeParams", ip);
    std::cout << std::endl;
}

void test_RequestMessage_serialize()
{
    // // 1. 直接从 LSPObject 转换
    // lsp::protocol::LSPObject obj = [> ... <];
    // auto result = lsp::transform::As<CompletionParams>(obj);

    // // 2. 从 variant 转换
    // std::variant<lsp::protocol::LSPArray, lsp::protocol::LSPObject> var = [> ... <];
    // auto result = lsp::transform::As<CompletionParams>(var);

    // // 3. 从 optional 转换
    // std::optional<lsp::protocol::LSPObject> opt = [> ... <];
    // auto result = lsp::transform::As<CompletionParams>(opt); // 返回 optional<CompletionParams>

    // // 4. 从复杂的嵌套类型转换
    // std::optional<std::variant<lsp::protocol::LSPArray, lsp::protocol::LSPObject>> complex = [> ... <];
    // auto result = lsp::transform::As<CompletionParams>(complex); // 返回 optional<CompletionParams>

    // // 5. 实际使用场景
    // if (request.params.has_value()) {
    //     // 直接处理 optional<variant<LSPArray, LSPObject>>
    //     auto completionParams = lsp::transform::As<lsp::protocol::CompletionParams>(request.params);
    //     if (completionParams.has_value()) {
    //         std::cout << "URI: " << completionParams->textDocument.uri << std::endl;
    //     }
    // }
    std::string json = R"({
        "jsonrpc":"2.0",
        "id":"4",
        "method":"textDocument/completion",
        "params":{
            "context":{"triggerKind":1},
            "partialResultToken":0,
            "position":{"character":12,"line":22},
            "textDocument":{"uri":"file://path/to_file.ts"},
            "workDoneToken":0
        }
    })";

    RequestMessage request;
    auto error = glz::read_json(request, json);

    if (error) {
        std::cerr << "Failed to parse JSON: " << glz::format_error(error, json) << std::endl;
    }

    std::cout << "jsonrpc: " << request.jsonrpc << std::endl;
    std::cout << "method: " << request.method << std::endl;
    std::visit([](const auto& id)
    {
        using T = std::decay_t<decltype(id)>;
        if constexpr (std::is_same_v<T, lsp::protocol::string>) {
            std::cout << "ID (string): " << id << std::endl;
        } else if constexpr (std::is_same_v<T, lsp::protocol::integer>) {
            std::cout << "ID (integer): " << id << std::endl;
        }
    }, request.id);

    auto completionParams = transform::As<CompletionParams>(request.params.value());
    std::cout << "URI: " << completionParams.textDocument.uri << std::endl;

    // std::visit([](const auto& value)
    // {
    //     std::cout << value;
    // }, request.id);

    // std::visit([](const auto& params) {

    // }, request.params.value());
}

void test_message()
{
    std::cout << "\n=== Test message.hpp ===" << std::endl;
    ResponseMessage response;
    response.id = "123";
    InitializeResult result;
    result.serverInfo.name = "TSL Language Server";
    result.serverInfo.version = "1.0.0";
    TextDocumentSyncOptions opts;
    opts.openClose = true;
    opts.change = TextDocumentSyncKind::kIncremental;
    result.capabilities.textDocumentSync = opts;

    CompletionParams comparams;
    comparams.textDocument.uri = "file://path/to_file.ts";
    comparams.position.character = 12;
    comparams.position.line = 22;
    comparams.context = CompletionContext{
        .triggerKind = CompletionTriggerKind::kInvoked,
        .triggerCharacter = std::nullopt
    };
    RequestMessage rm;
    rm.id = "4";
    rm.method = "textDocument/completion";
    rm.params = transform::LSPObject(comparams);

    print_json("ResponseMessage", response);
    print_json("rm", rm);
}

int main()
{
    // test_basic_conversion();
    // test_vector_conversion();
    // test_json_string();
    // test_basic_types();
    // test_capabilities();
    test_message();
    test_RequestMessage_serialize();
    return 0;
}
