#include <cmath>
#include <limits>
#include "../../src/protocol/detail/basic_types.hpp"
#include "./lsp_any_test.hpp"

namespace lsp::test
{

    // ==================== LSPAnyTests 实现 ====================

    void LSPAnyTests::registerTests(TestRunner& runner)
    {
        // 构造函数测试
        runner.addTest("默认构造函数", testDefaultConstructor);
        runner.addTest("浮点数构造函数", testDecimalConstructor);
        runner.addTest("布尔构造函数", testBooleanConstructor);
        runner.addTest("字符串构造函数", testStringConstructor);
        runner.addTest("C字符串构造函数", testCStringConstructor);
        runner.addTest("空指针构造函数", testNullptrConstructor);
        runner.addTest("LSPObject构造函数", testLSPObjectConstructor);
        runner.addTest("LSPArray构造函数", testLSPArrayConstructor);

        // 拷贝和移动测试
        runner.addTest("拷贝构造函数", testCopyConstructor);
        runner.addTest("移动构造函数", testMoveConstructor);
        runner.addTest("拷贝赋值", testCopyAssignment);
        runner.addTest("移动赋值", testMoveAssignment);

        // 赋值操作符测试
        runner.addTest("浮点数赋值", testDecimalAssignment);
        runner.addTest("布尔赋值", testBooleanAssignment);
        runner.addTest("字符串赋值", testStringAssignment);
        runner.addTest("空指针赋值", testNullptrAssignment);
        runner.addTest("LSPObject赋值", testLSPObjectAssignment);
        runner.addTest("LSPArray赋值", testLSPArrayAssignment);

        // 类型检查测试
        runner.addTest("Is类型检查", testIsMethod);
        runner.addTest("Get获取值", testGetMethod);

        // 访问者模式测试
        runner.addTest("Visit访问者", testVisitMethod);

        // 整数模板测试
        runner.addTest("有符号整数模板", testIntegerTemplateSignedTypes);
        runner.addTest("无符号整数模板", testIntegerTemplateUnsignedTypes);
        runner.addTest("整数边界测试", testIntegerTemplateBoundaries);

        // 复杂场景测试
        runner.addTest("嵌套LSPObject", testNestedLSPObject);
        runner.addTest("嵌套LSPArray", testNestedLSPArray);
        runner.addTest("混合嵌套", testMixedNesting);
        runner.addTest("类型转换", testTypeConversion);

        // 边界情况测试
        runner.addTest("浮点精度", testFloatPrecision);
        runner.addTest("大数字", testLargeNumbers);
        runner.addTest("空容器", testEmptyContainers);
    }

    // ==================== 构造函数测试 ====================

    TestResult LSPAnyTests::testDefaultConstructor()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny any;
        assertTrue(any.Is<std::nullptr_t>(), "默认构造应该是nullptr类型");

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

    TestResult LSPAnyTests::testDecimalConstructor()
    {
        TestResult result;
        result.passed = true;

        protocol::decimal value = 3.14;
        protocol::LSPAny any(value);

        assertTrue(any.Is<protocol::decimal>(), "应该是decimal类型");
        assertEqual(value, any.Get<protocol::decimal>(), "值应该相等");

        // 测试 float 构造
        float fValue = 2.5f;
        protocol::LSPAny anyFloat(fValue);
        assertTrue(anyFloat.Is<protocol::decimal>(), "float应该转为decimal类型");

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

    TestResult LSPAnyTests::testBooleanConstructor()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny anyTrue(true);
        protocol::LSPAny anyFalse(false);

        assertTrue(anyTrue.Is<protocol::boolean>(), "应该是boolean类型");
        assertTrue(anyFalse.Is<protocol::boolean>(), "应该是boolean类型");
        assertEqual(true, anyTrue.Get<protocol::boolean>(), "值应该是true");
        assertEqual(false, anyFalse.Get<protocol::boolean>(), "值应该是false");

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

    TestResult LSPAnyTests::testStringConstructor()
    {
        TestResult result;
        result.passed = true;

        protocol::string value = "Hello, LSP!";
        protocol::LSPAny any(value);

        assertTrue(any.Is<protocol::string>(), "应该是string类型");
        assertEqual(value, any.Get<protocol::string>(), "值应该相等");

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

    TestResult LSPAnyTests::testCStringConstructor()
    {
        TestResult result;
        result.passed = true;

        const char* value = "C String";
        protocol::LSPAny any(value);

        assertTrue(any.Is<protocol::string>(), "应该是string类型");
        assertEqual(std::string(value), any.Get<protocol::string>(), "值应该相等");

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

    TestResult LSPAnyTests::testNullptrConstructor()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny any(nullptr);

        assertTrue(any.Is<std::nullptr_t>(), "应该是nullptr类型");

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

    TestResult LSPAnyTests::testLSPObjectConstructor()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPObject obj;
        obj["key1"] = protocol::LSPAny(42);
        obj["key2"] = protocol::LSPAny("value");

        protocol::LSPAny any(obj);

        assertTrue(any.Is<protocol::LSPObject>(), "应该是LSPObject类型");
        const auto& retrievedObj = any.Get<protocol::LSPObject>();
        assertTrue(retrievedObj.count("key1") > 0, "应该包含key1");
        assertTrue(retrievedObj.count("key2") > 0, "应该包含key2");

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

    TestResult LSPAnyTests::testLSPArrayConstructor()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPArray arr;
        arr.push_back(protocol::LSPAny(1));
        arr.push_back(protocol::LSPAny(2));
        arr.push_back(protocol::LSPAny(3));

        protocol::LSPAny any(arr);

        assertTrue(any.Is<protocol::LSPArray>(), "应该是LSPArray类型");
        const auto& retrievedArr = any.Get<protocol::LSPArray>();
        assertTrue(retrievedArr.size() == 3, "数组大小应该是3");

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

    // ==================== 拷贝和移动测试 ====================

    TestResult LSPAnyTests::testCopyConstructor()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny original(42);
        protocol::LSPAny copy(original);

        assertTrue(copy.Is<protocol::integer>(), "拷贝应该保持类型");
        assertEqual(42, copy.Get<protocol::integer>(), "拷贝应该保持值");
        assertEqual(42, original.Get<protocol::integer>(), "原值不应改变");

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

    TestResult LSPAnyTests::testMoveConstructor()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny original(protocol::string("Move me"));
        protocol::LSPAny moved(std::move(original));

        assertTrue(moved.Is<protocol::string>(), "移动应该保持类型");
        assertEqual(std::string("Move me"), moved.Get<protocol::string>(), "移动应该保持值");

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

    TestResult LSPAnyTests::testCopyAssignment()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny original(42);
        protocol::LSPAny target(nullptr);
        target = original;

        assertTrue(target.Is<protocol::integer>(), "赋值应该保持类型");
        assertEqual(42, target.Get<protocol::integer>(), "赋值应该保持值");

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

    TestResult LSPAnyTests::testMoveAssignment()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny original(protocol::string("Move me"));
        protocol::LSPAny target(nullptr);
        target = std::move(original);

        assertTrue(target.Is<protocol::string>(), "移动赋值应该保持类型");
        assertEqual(std::string("Move me"), target.Get<protocol::string>(), "移动赋值应该保持值");

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

    // ==================== 赋值操作符测试 ====================

    TestResult LSPAnyTests::testDecimalAssignment()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny any(nullptr);
        any = 2.718;

        assertTrue(any.Is<protocol::decimal>(), "赋值后应该是decimal类型");
        assertEqual(2.718, any.Get<protocol::decimal>(), "赋值后值应该正确");

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

    TestResult LSPAnyTests::testBooleanAssignment()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny any(nullptr);
        any = true;

        assertTrue(any.Is<protocol::boolean>(), "赋值后应该是boolean类型");
        assertEqual(true, any.Get<protocol::boolean>(), "赋值后值应该正确");

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

    TestResult LSPAnyTests::testStringAssignment()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny any(nullptr);
        any = protocol::string("Assigned");

        assertTrue(any.Is<protocol::string>(), "赋值后应该是string类型");
        assertEqual(std::string("Assigned"), any.Get<protocol::string>(), "赋值后值应该正确");

        // 测试 C 字符串赋值
        any = "C String";
        assertEqual(std::string("C String"), any.Get<protocol::string>(), "C字符串赋值应该正确");

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

    TestResult LSPAnyTests::testNullptrAssignment()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny any(42);
        any = nullptr;

        assertTrue(any.Is<std::nullptr_t>(), "赋值后应该是nullptr类型");

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

    TestResult LSPAnyTests::testLSPObjectAssignment()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPObject obj;
        obj["test"] = protocol::LSPAny(999);

        protocol::LSPAny any(nullptr);
        any = obj;

        assertTrue(any.Is<protocol::LSPObject>(), "赋值后应该是LSPObject类型");
        const auto& retrievedObj = any.Get<protocol::LSPObject>();
        assertTrue(retrievedObj.count("test") > 0, "应该包含test键");

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

    TestResult LSPAnyTests::testLSPArrayAssignment()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPArray arr;
        arr.push_back(protocol::LSPAny(10));
        arr.push_back(protocol::LSPAny(20));

        protocol::LSPAny any(nullptr);
        any = arr;

        assertTrue(any.Is<protocol::LSPArray>(), "赋值后应该是LSPArray类型");
        const auto& retrievedArr = any.Get<protocol::LSPArray>();
        assertTrue(retrievedArr.size() == 2, "数组大小应该是2");

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

    // ==================== 类型检查测试 ====================

    TestResult LSPAnyTests::testIsMethod()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny intAny(42);
        assertTrue(intAny.Is<protocol::integer>(), "Is应该正确识别integer");
        assertFalse(intAny.Is<protocol::string>(), "Is应该正确排除string");
        assertFalse(intAny.Is<protocol::decimal>(), "Is应该正确排除decimal");

        protocol::LSPAny strAny(protocol::string("test"));
        assertTrue(strAny.Is<protocol::string>(), "Is应该正确识别string");
        assertFalse(strAny.Is<protocol::integer>(), "Is应该正确排除integer");

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

    TestResult LSPAnyTests::testGetMethod()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny any(42);
        assertEqual(42, any.Get<protocol::integer>(), "Get应该返回正确的值");

        // 修改值
        any.Get<protocol::integer>() = 100;
        assertEqual(100, any.Get<protocol::integer>(), "Get应该返回可修改的引用");

        // const Get 测试
        const protocol::LSPAny constAny(200);
        assertEqual(200, constAny.Get<protocol::integer>(), "const Get应该正常工作");

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

    // ==================== 访问者模式测试 ====================

    TestResult LSPAnyTests::testVisitMethod()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny intAny(42);
        protocol::LSPAny strAny(protocol::string("hello"));
        protocol::LSPAny boolAny(true);

        // 测试 const Visit
        auto visitor = [](const auto& value) -> std::string {
            using T = std::decay_t<decltype(value)>;
            if constexpr (std::is_same_v<T, protocol::integer>)
            {
                return "integer:" + std::to_string(value);
            }
            else if constexpr (std::is_same_v<T, protocol::string>)
            {
                return "string:" + value;
            }
            else if constexpr (std::is_same_v<T, protocol::boolean>)
            {
                return value ? "bool:true" : "bool:false";
            }
            else
            {
                return "other";
            }
        };

        std::string result1 = intAny.Visit(visitor);
        assertEqual(std::string("integer:42"), result1, "Visit应该正确访问integer");

        std::string result2 = strAny.Visit(visitor);
        assertEqual(std::string("string:hello"), result2, "Visit应该正确访问string");

        std::string result3 = boolAny.Visit(visitor);
        assertEqual(std::string("bool:true"), result3, "Visit应该正确访问boolean");

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

    // ==================== 整数模板测试 ====================

    TestResult LSPAnyTests::testIntegerTemplateSignedTypes()
    {
        TestResult result;
        result.passed = true;

        // 测试各种有符号整数类型
        protocol::LSPAny anyInt8(static_cast<int8_t>(-10));
        assertTrue(anyInt8.Is<protocol::integer>(), "int8_t应该转为integer");
        assertEqual(-10, anyInt8.Get<protocol::integer>(), "int8_t值应该正确");

        protocol::LSPAny anyInt16(static_cast<int16_t>(-1000));
        assertTrue(anyInt16.Is<protocol::integer>(), "int16_t应该转为integer");
        assertEqual(-1000, anyInt16.Get<protocol::integer>(), "int16_t值应该正确");

        protocol::LSPAny anyInt64(static_cast<int64_t>(100000));
        assertTrue(anyInt64.Is<protocol::integer>(), "int64_t应该转为integer");
        assertEqual(100000, anyInt64.Get<protocol::integer>(), "int64_t值应该正确");

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

    TestResult LSPAnyTests::testIntegerTemplateUnsignedTypes()
    {
        TestResult result;
        result.passed = true;

        // 测试各种无符号整数类型 - 无符号整数应该存储为uinteger
        protocol::LSPAny anyUint8(static_cast<uint8_t>(255));
        assertTrue(anyUint8.Is<protocol::uinteger>(), "uint8_t应该转为uinteger");
        assertEqual(255u, anyUint8.Get<protocol::uinteger>(), "uint8_t值应该正确");

        protocol::LSPAny anyUint16(static_cast<uint16_t>(5000));
        assertTrue(anyUint16.Is<protocol::uinteger>(), "uint16_t应该转为uinteger");
        assertEqual(5000u, anyUint16.Get<protocol::uinteger>(), "uint16_t值应该正确");

        protocol::LSPAny anySize(static_cast<size_t>(12345));
        assertTrue(anySize.Is<protocol::uinteger>(), "size_t应该转为uinteger");
        assertEqual(12345u, anySize.Get<protocol::uinteger>(), "size_t值应该正确");

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

    TestResult LSPAnyTests::testIntegerTemplateBoundaries()
    {
        TestResult result;
        result.passed = true;

        // 测试 int32 边界
        protocol::LSPAny anyMax(std::numeric_limits<int32_t>::max());
        assertTrue(anyMax.Is<protocol::integer>(), "int32_max应该是integer");
        assertEqual(std::numeric_limits<int32_t>::max(), anyMax.Get<protocol::integer>(), "int32_max值应该正确");

        protocol::LSPAny anyMin(std::numeric_limits<int32_t>::min());
        assertTrue(anyMin.Is<protocol::integer>(), "int32_min应该是integer");
        assertEqual(std::numeric_limits<int32_t>::min(), anyMin.Get<protocol::integer>(), "int32_min值应该正确");

        // 测试超出 int32 范围的 int64
        int64_t largeValue = static_cast<int64_t>(std::numeric_limits<int32_t>::max()) + 1;
        protocol::LSPAny anyLarge(largeValue);
        assertTrue(anyLarge.Is<protocol::decimal>(), "超出int32范围应该转为decimal");

        // 测试 uint32 边界
        protocol::LSPAny anyUintMax(std::numeric_limits<uint32_t>::max());
        assertTrue(anyUintMax.Is<protocol::uinteger>(), "uint32_max应该是uinteger");
        assertEqual(std::numeric_limits<uint32_t>::max(), anyUintMax.Get<protocol::uinteger>(), "uint32_max值应该正确");

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

    // ==================== 复杂场景测试 ====================

    TestResult LSPAnyTests::testNestedLSPObject()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPObject innerObj;
        innerObj["inner_key"] = protocol::LSPAny(42);

        protocol::LSPObject outerObj;
        outerObj["outer_key"] = protocol::LSPAny(innerObj);
        outerObj["name"] = protocol::LSPAny(protocol::string("test"));

        protocol::LSPAny any(outerObj);

        assertTrue(any.Is<protocol::LSPObject>(), "应该是LSPObject类型");
        const auto& obj = any.Get<protocol::LSPObject>();
        assertTrue(obj.count("outer_key") > 0, "应该包含outer_key");
        assertTrue(obj.count("name") > 0, "应该包含name");

        const auto& inner = obj.at("outer_key");
        assertTrue(inner.Is<protocol::LSPObject>(), "嵌套值应该是LSPObject");

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

    TestResult LSPAnyTests::testNestedLSPArray()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPArray innerArr;
        innerArr.push_back(protocol::LSPAny(1));
        innerArr.push_back(protocol::LSPAny(2));

        protocol::LSPArray outerArr;
        outerArr.push_back(protocol::LSPAny(innerArr));
        outerArr.push_back(protocol::LSPAny(protocol::string("text")));

        protocol::LSPAny any(outerArr);

        assertTrue(any.Is<protocol::LSPArray>(), "应该是LSPArray类型");
        const auto& arr = any.Get<protocol::LSPArray>();
        assertTrue(arr.size() == 2, "外层数组大小应该是2");
        assertTrue(arr[0].Is<protocol::LSPArray>(), "第一个元素应该是LSPArray");

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

    TestResult LSPAnyTests::testMixedNesting()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPArray arr;
        arr.push_back(protocol::LSPAny(1));
        arr.push_back(protocol::LSPAny(protocol::string("two")));
        arr.push_back(protocol::LSPAny(3.0));

        protocol::LSPObject obj;
        obj["array"] = protocol::LSPAny(arr);
        obj["number"] = protocol::LSPAny(42);
        obj["flag"] = protocol::LSPAny(true);

        protocol::LSPAny any(obj);

        assertTrue(any.Is<protocol::LSPObject>(), "应该是LSPObject类型");
        const auto& retrievedObj = any.Get<protocol::LSPObject>();
        assertTrue(retrievedObj.count("array") > 0, "应该包含array");
        assertTrue(retrievedObj.at("array").Is<protocol::LSPArray>(), "array应该是LSPArray类型");

        const auto& retrievedArr = retrievedObj.at("array").Get<protocol::LSPArray>();
        assertTrue(retrievedArr.size() == 3, "数组大小应该是3");

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

    TestResult LSPAnyTests::testTypeConversion()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPAny any(42);
        assertTrue(any.Is<protocol::integer>(), "初始应该是integer");

        // 改变类型
        any = protocol::string("now a string");
        assertTrue(any.Is<protocol::string>(), "现在应该是string");
        assertFalse(any.Is<protocol::integer>(), "不应该再是integer");

        // 再次改变
        any = 3.14;
        assertTrue(any.Is<protocol::decimal>(), "现在应该是decimal");
        assertFalse(any.Is<protocol::string>(), "不应该再是string");

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

    // ==================== 边界情况测试 ====================

    TestResult LSPAnyTests::testFloatPrecision()
    {
        TestResult result;
        result.passed = true;

        float fValue = 1.23456789f;
        protocol::LSPAny anyFloat(fValue);

        assertTrue(anyFloat.Is<protocol::decimal>(), "float应该转为decimal");

        // 注意：float 转为 double 可能有精度变化，这里只是验证类型转换正确
        protocol::decimal retrieved = anyFloat.Get<protocol::decimal>();
        assertTrue(std::abs(retrieved - static_cast<double>(fValue)) < 1e-6,
                   "转换后的值应该接近原值");

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

    TestResult LSPAnyTests::testLargeNumbers()
    {
        TestResult result;
        result.passed = true;

        // 测试大的 uint64 值转为 decimal
        uint64_t largeUint = 10000000000ULL; // 超出 uint32 范围
        protocol::LSPAny anyLarge(largeUint);

        assertTrue(anyLarge.Is<protocol::decimal>(), "大整数应该转为decimal");

        protocol::decimal retrieved = anyLarge.Get<protocol::decimal>();
        assertTrue(std::abs(retrieved - static_cast<double>(largeUint)) < 1.0,
                   "转换后的值应该接近原值");

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

    TestResult LSPAnyTests::testEmptyContainers()
    {
        TestResult result;
        result.passed = true;

        protocol::LSPObject emptyObj;
        protocol::LSPAny anyObj(emptyObj);

        assertTrue(anyObj.Is<protocol::LSPObject>(), "应该是LSPObject类型");
        const auto& obj = anyObj.Get<protocol::LSPObject>();
        assertTrue(obj.empty(), "对象应该为空");

        protocol::LSPArray emptyArr;
        protocol::LSPAny anyArr(emptyArr);

        assertTrue(anyArr.Is<protocol::LSPArray>(), "应该是LSPArray类型");
        const auto& arr = anyArr.Get<protocol::LSPArray>();
        assertTrue(arr.empty(), "数组应该为空");

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

} // namespace lsp::test
