#include <glaze/glaze.hpp>
#include "facade_test.hpp"
#include "../../src/protocol/transform/facade.hpp"
#include "../../src/protocol/detail/basic_types.hpp"

namespace lsp::test
{
    // 测试用结构体
    struct TestPerson
    {
        std::string name;
        int age;
    };

    struct TestConfig
    {
        std::string version;
        bool enabled;
        std::vector<int> ports;
    };
}

// Glaze 元数据
template<>
struct glz::meta<lsp::test::TestPerson>
{
    using T = lsp::test::TestPerson;
    static constexpr auto value = object(
        "name", &T::name,
        "age", &T::age
    );
};

template<>
struct glz::meta<lsp::test::TestConfig>
{
    using T = lsp::test::TestConfig;
    static constexpr auto value = object(
        "version", &T::version,
        "enabled", &T::enabled,
        "ports", &T::ports
    );
};

namespace lsp::test
{
    void FacadeTests::registerTests(TestRunner& runner)
    {
        // Serialize/Deserialize 测试
        runner.addTest("Facade - 序列化简单结构体", testSerializeSimpleStruct);
        runner.addTest("Facade - 序列化复杂结构体", testSerializeComplexStruct);
        runner.addTest("Facade - 序列化LSPAny", testSerializeLSPAny);
        runner.addTest("Facade - 反序列化简单结构体", testDeserializeSimpleStruct);
        runner.addTest("Facade - 反序列化复杂结构体", testDeserializeComplexStruct);
        runner.addTest("Facade - 反序列化无效JSON", testDeserializeInvalidJSON);
        runner.addTest("Facade - 序列化反序列化往返", testSerializeDeserializeRoundtrip);

        // check 命名空间测试
        runner.addTest("Facade - Check IsObject", testCheckIsObject);
        runner.addTest("Facade - Check IsArray", testCheckIsArray);
        runner.addTest("Facade - Check IsString", testCheckIsString);
        runner.addTest("Facade - Check IsNumber", testCheckIsNumber);
        runner.addTest("Facade - Check IsBool", testCheckIsBool);
        runner.addTest("Facade - Check IsNull", testCheckIsNull);
        runner.addTest("Facade - Check 多类型检查", testCheckMultipleTypes);

        // debug 命名空间测试
        runner.addTest("Facade - Debug GetTypeName", testDebugGetTypeName);
        runner.addTest("Facade - Debug GetIdString (int)", testDebugGetIdStringInt);
        runner.addTest("Facade - Debug GetIdString (string)", testDebugGetIdStringString);
    }

    // ==================== Serialize/Deserialize 测试 ====================

    TestResult FacadeTests::testSerializeSimpleStruct()
    {
        TestResult result;
        result.passed = true;

        TestPerson person{"Alice", 30};
        auto json_opt = transform::Serialize(person);

        assertTrue(json_opt.has_value(), "序列化应该成功");
        const auto& json = json_opt.value();
        assertTrue(json.find("Alice") != std::string::npos, "JSON应该包含'Alice'");
        assertTrue(json.find("30") != std::string::npos, "JSON应该包含'30'");

        result.message = "成功";
        return result;
    }

    TestResult FacadeTests::testSerializeComplexStruct()
    {
        TestResult result;
        result.passed = true;

        TestConfig config{"1.0.0", true, {8080, 8081, 8082}};
        auto json_opt = transform::Serialize(config);

        assertTrue(json_opt.has_value(), "序列化应该成功");
        const auto& json = json_opt.value();
        assertTrue(json.find("1.0.0") != std::string::npos, "JSON应该包含版本号");
        assertTrue(json.find("true") != std::string::npos, "JSON应该包含enabled");
        assertTrue(json.find("8080") != std::string::npos, "JSON应该包含端口");

        result.message = "成功";
        return result;
    }

    TestResult FacadeTests::testSerializeLSPAny()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPObject obj;
        obj["key"] = protocol::LSPAny(42);
        obj["name"] = protocol::LSPAny("test");
        protocol::LSPAny any(obj);

        auto json_opt = transform::Serialize(any);
        assertTrue(json_opt.has_value(), "序列化LSPAny应该成功");

        result.message = "成功";
        return result;
    }

    TestResult FacadeTests::testDeserializeSimpleStruct()
    {
        TestResult result;
        result.passed = true;

        std::string json = R"({"name":"Bob","age":25})";
        auto person_opt = transform::Deserialize<TestPerson>(json);

        assertTrue(person_opt.has_value(), "反序列化应该成功");
        const auto& person = person_opt.value();
        assertEqual(std::string("Bob"), person.name, "名字应该为'Bob'");
        assertEqual(25, person.age, "年龄应该为25");

        result.message = "成功";
        return result;
    }

    TestResult FacadeTests::testDeserializeComplexStruct()
    {
        TestResult result;
        result.passed = true;

        std::string json = R"({"version":"2.0.0","enabled":false,"ports":[9000,9001,9002]})";
        auto config_opt = transform::Deserialize<TestConfig>(json);

        assertTrue(config_opt.has_value(), "反序列化应该成功");
        const auto& config = config_opt.value();
        assertEqual(std::string("2.0.0"), config.version, "版本应该为'2.0.0'");
        assertEqual(false, config.enabled, "enabled应该为false");
        assertEqual(size_t(3), config.ports.size(), "应该有3个端口");
        assertEqual(9000, config.ports[0], "第一个端口应该为9000");

        result.message = "成功";
        return result;
    }

    TestResult FacadeTests::testDeserializeInvalidJSON()
    {
        TestResult result;
        result.passed = true;

        std::string json = R"({"invalid json syntax)";
        auto person_opt = transform::Deserialize<TestPerson>(json);

        assertFalse(person_opt.has_value(), "反序列化无效JSON应该失败");

        result.message = "成功";
        return result;
    }

    TestResult FacadeTests::testSerializeDeserializeRoundtrip()
    {
        TestResult result;
        result.passed = true;

        TestPerson original{"Charlie", 35};
        
        auto json_opt = transform::Serialize(original);
        assertTrue(json_opt.has_value(), "序列化应该成功");

        auto person_opt = transform::Deserialize<TestPerson>(json_opt.value());
        assertTrue(person_opt.has_value(), "反序列化应该成功");

        const auto& restored = person_opt.value();
        assertEqual(original.name, restored.name, "名字应该保持一致");
        assertEqual(original.age, restored.age, "年龄应该保持一致");

        result.message = "成功";
        return result;
    }

    // ==================== check 命名空间测试 ====================

    TestResult FacadeTests::testCheckIsObject()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPObject obj;
        obj["key"] = protocol::LSPAny(1);
        protocol::LSPAny any(obj);

        assertTrue(transform::check::IsObject(any), "应该识别为object");

        protocol::LSPAny not_obj(42);
        assertFalse(transform::check::IsObject(not_obj), "integer不应该识别为object");

        result.message = "成功";
        return result;
    }

    TestResult FacadeTests::testCheckIsArray()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPArray arr;
        arr.push_back(protocol::LSPAny(1));
        protocol::LSPAny any(arr);

        assertTrue(transform::check::IsArray(any), "应该识别为array");

        protocol::LSPAny not_arr("string");
        assertFalse(transform::check::IsArray(not_arr), "string不应该识别为array");

        result.message = "成功";
        return result;
    }

    TestResult FacadeTests::testCheckIsString()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny any("hello");
        assertTrue(transform::check::IsString(any), "应该识别为string");

        protocol::LSPAny not_str(42);
        assertFalse(transform::check::IsString(not_str), "integer不应该识别为string");

        result.message = "成功";
        return result;
    }

    TestResult FacadeTests::testCheckIsNumber()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny int_any(42);
        assertTrue(transform::check::IsNumber(int_any), "integer应该是数字");

        protocol::LSPAny uint_any(100u);
        assertTrue(transform::check::IsNumber(uint_any), "uinteger应该是数字");

        protocol::LSPAny decimal_any(3.14);
        assertTrue(transform::check::IsNumber(decimal_any), "decimal应该是数字");

        protocol::LSPAny not_num("string");
        assertFalse(transform::check::IsNumber(not_num), "string不应该是数字");

        result.message = "成功";
        return result;
    }

    TestResult FacadeTests::testCheckIsBool()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny any(true);
        assertTrue(transform::check::IsBool(any), "应该识别为bool");

        protocol::LSPAny not_bool(42);
        assertFalse(transform::check::IsBool(not_bool), "integer不应该识别为bool");

        result.message = "成功";
        return result;
    }

    TestResult FacadeTests::testCheckIsNull()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny any(nullptr);
        assertTrue(transform::check::IsNull(any), "应该识别为null");

        protocol::LSPAny not_null(42);
        assertFalse(transform::check::IsNull(not_null), "integer不应该识别为null");

        result.message = "成功";
        return result;
    }

    TestResult FacadeTests::testCheckMultipleTypes()
    {
        TestResult result;
        result.passed = true;

        // 测试一个值不能同时是多种类型
        protocol::LSPAny any(42);
        assertTrue(transform::check::IsNumber(any), "应该是数字");
        assertFalse(transform::check::IsString(any), "不应该是字符串");
        assertFalse(transform::check::IsBool(any), "不应该是布尔值");
        assertFalse(transform::check::IsNull(any), "不应该是null");
        assertFalse(transform::check::IsArray(any), "不应该是数组");
        assertFalse(transform::check::IsObject(any), "不应该是对象");

        result.message = "成功";
        return result;
    }

    // ==================== debug 命名空间测试 ====================

    TestResult FacadeTests::testDebugGetTypeName()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny obj_any(protocol::LSPObject{});
        assertEqual(std::string("LSPObject"), transform::debug::GetTypeName(obj_any), 
                   "类型名应该为'LSPObject'");

        protocol::LSPAny arr_any(protocol::LSPArray{});
        assertEqual(std::string("LSPArray"), transform::debug::GetTypeName(arr_any), 
                   "类型名应该为'LSPArray'");

        protocol::LSPAny str_any("test");
        assertEqual(std::string("string"), transform::debug::GetTypeName(str_any), 
                   "类型名应该为'string'");

        protocol::LSPAny int_any(42);
        assertEqual(std::string("integer"), transform::debug::GetTypeName(int_any), 
                   "类型名应该为'integer'");

        protocol::LSPAny uint_any(100u);
        assertEqual(std::string("uinteger"), transform::debug::GetTypeName(uint_any), 
                   "类型名应该为'uinteger'");

        protocol::LSPAny decimal_any(3.14);
        assertEqual(std::string("decimal"), transform::debug::GetTypeName(decimal_any), 
                   "类型名应该为'decimal'");

        protocol::LSPAny bool_any(true);
        assertEqual(std::string("boolean"), transform::debug::GetTypeName(bool_any), 
                   "类型名应该为'boolean'");

        protocol::LSPAny null_any(nullptr);
        assertEqual(std::string("null"), transform::debug::GetTypeName(null_any), 
                   "类型名应该为'null'");

        result.message = "成功";
        return result;
    }

    TestResult FacadeTests::testDebugGetIdStringInt()
    {
        TestResult result;
        result.passed = true;

        std::variant<int, std::string> id = 123;
        std::string id_str = transform::debug::GetIdString(id);
        assertEqual(std::string("123"), id_str, "int id应该转换为'123'");

        result.message = "成功";
        return result;
    }

    TestResult FacadeTests::testDebugGetIdStringString()
    {
        TestResult result;
        result.passed = true;

        std::variant<int, std::string> id = std::string("abc-123-def");
        std::string id_str = transform::debug::GetIdString(id);
        assertEqual(std::string("abc-123-def"), id_str, "string id应该保持为'abc-123-def'");

        result.message = "成功";
        return result;
    }

} // namespace lsp::test
