/*
 * Copyright (c) 2024 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <chrono>
#include <iostream>
#include <mc/exception.h>
#include <mc/log.h>
#include <mc/module.h>
#include <mc/variant.h>
#include <thread>

/**
 * @brief 测试 devices 模块加载
 * @return 测试是否成功
 */
bool test_devices_module()
{
    try {
        ilog("=== 1. Verify devices module load ===");

        auto devices_module = mc::load_module("mc.devices");
        if (!devices_module) {
            elog("cannot load devices module");
            return false;
        }

        ilog("successfully loaded module: ${name} v${version}",
             ("name", devices_module->name())("version", devices_module->version()));

        auto devices_factory = devices_module->get_factory();
        auto sensor_obj      = devices_factory->try_create_object("Sensor");
        if (sensor_obj) {
            sensor_obj->invoke_method("setName", {mc::variant("test_sensor")});
            auto name_result = sensor_obj->invoke_method("getName", {});
            ilog("✓ devices module sensor test succeeded: ${name}", ("name", name_result.as<std::string>()));
        }

        return true;
    } catch (const mc::exception& e) {
        elog("devices module test failed: ${msg}", ("msg", e.what()));
        return false;
    } catch (const std::exception& e) {
        elog("devices module test failed: ${msg}", ("msg", e.what()));
        return false;
    }
}

/**
 * @brief 测试 network 模块加载
 * @return 测试是否成功
 */
bool test_network_module()
{
    try {
        ilog("=== 2. Verify network module load ===");

        auto network_module = mc::load_module("mc.network");
        if (!network_module) {
            elog("cannot load network module");
            return false;
        }

        ilog("successfully loaded network module: ${name}", ("name", network_module->name()));

        auto network_factory = network_module->get_factory();
        auto client_obj      = network_factory->try_create_object("NetworkClient");
        if (client_obj) {
            auto connect_result = client_obj->invoke_method("connect", {mc::variant("127.0.0.1"), mc::variant(8080)});
            ilog("✓ network module connection test: ${result}", ("result", connect_result.as<bool>()));

            auto host_result = client_obj->invoke_method("getHost", {});
            ilog("✓ connected host: ${host}", ("host", host_result.as<std::string>()));
        }

        return true;
    } catch (const mc::exception& e) {
        elog("network module test failed: ${msg}", ("msg", e.what()));
        return false;
    } catch (const std::exception& e) {
        elog("network module test failed: ${msg}", ("msg", e.what()));
        return false;
    }
}

/**
 * @brief 测试 protocol 模块加载
 * @return 测试是否成功
 */
bool test_protocol_module()
{
    try {
        ilog("=== 3. Verify protocol module load (init.so mode) ===");

        auto protocol_module = mc::load_module("mc.protocol");
        if (!protocol_module) {
            elog("cannot load protocol module");
            return false;
        }

        ilog("successfully loaded protocol module: ${name}", ("name", protocol_module->name()));

        auto protocol_factory = protocol_module->get_factory();
        auto handler_obj      = protocol_factory->try_create_object("ProtocolHandler");
        if (handler_obj) {
            auto request_result = handler_obj->invoke_method("handleRequest", {mc::variant("test request")});
            ilog("✓ protocol module handled request: ${result}", ("result", request_result.as<std::string>()));

            auto version_result = handler_obj->invoke_method("getVersionString", {});
            ilog("✓ protocol version: ${version}", ("version", version_result.as<std::string>()));
        }

        return true;
    } catch (const mc::exception& e) {
        elog("protocol module test failed: ${msg}", ("msg", e.what()));
        return false;
    } catch (const std::exception& e) {
        elog("protocol module test failed: ${msg}", ("msg", e.what()));
        return false;
    }
}

/**
 * @brief 测试 database 模块加载
 * @return 测试是否成功
 */
bool test_database_module()
{
    try {
        ilog("=== 4. Verify nested-path database module load ===");

        auto database_module = mc::load_module("mc.test.database");
        if (!database_module) {
            elog("cannot load mc.test.database module");
            return false;
        }

        ilog("successfully loaded database module: ${name}", ("name", database_module->name()));

        auto database_factory = database_module->get_factory();
        auto db_obj           = database_factory->try_create_object("DbConnection");
        if (db_obj) {
            auto connect_result = db_obj->invoke_method("connect", {mc::variant("localhost"), mc::variant("test_db")});
            ilog("✓ database module connection test: ${result}", ("result", connect_result.as<bool>()));

            auto db_name_result = db_obj->invoke_method("getDatabaseName", {});
            ilog("✓ database name: ${name}", ("name", db_name_result.as<std::string>()));

            auto query_result = db_obj->invoke_method("executeQuery", {mc::variant("SELECT * FROM test")});
            // 获取查询结果的第一行
            auto results = query_result.as<std::vector<std::string>>();
            if (!results.empty()) {
                ilog("✓ query result: ${result}", ("result", results[0]));
            }
        }

        return true;
    } catch (const mc::exception& e) {
        elog("database module test failed: ${msg}", ("msg", e.what()));
        return false;
    } catch (const std::exception& e) {
        elog("database module test failed: ${msg}", ("msg", e.what()));
        return false;
    }
}

/**
 * @brief 模块路径查找验证总结
 */
void test_module_path_summary()
{
    ilog("=== 5. Module path lookup summary ===");
    ilog("✓ mc.devices -> modules/mc/devices.so (standard mode)");
    ilog("✓ mc.network -> modules/mc/network.so (standard mode)");
    ilog("✓ mc.protocol -> modules/mc/protocol/init.so (init.so mode)");
    ilog("✓ mc.test.database -> modules/mc/test/database.so (deep path mode)");
    ilog("all module path lookup tests completed!");
}

/**
 * @brief 测试模块两阶段卸载机制
 * @return 测试是否成功
 */
bool test_two_phase_unload()
{
    try {
        ilog("=== 6. Two-phase module unload verification ===");
        ilog("Verify unload() only decreases refcount; actual unload requires releasing all module_ptr");

        auto& module_manager = mc::get_module_manager();

        // 6.1 保存模块引用以验证两阶段卸载
        ilog("=== 6.1 Save module ref for two-phase unload ===");

        // 重新获取模块引用,确保我们持有 module_ptr
        auto devices_module_ref = mc::load_module("mc.devices");
        auto network_module_ref = mc::load_module("mc.network");

        if (devices_module_ref) {
            auto factory = devices_module_ref->get_factory();
            // 通过创建一个临时对象来调用函数,或者尝试获取元数据来调用静态方法
            auto temp_obj = factory->try_create_object("Sensor");
            if (temp_obj) {
                // 目前通过一个虚拟对象调用,实际上这个函数应该是模块级别的
                ilog("devices module loaded");
            }
        }

        if (network_module_ref) {
            auto factory  = network_module_ref->get_factory();
            auto temp_obj = factory->try_create_object("NetworkClient");
            if (temp_obj) {
                ilog("network module loaded");
            }
        }

        // 6.2 调用 unload() - 第一阶段卸载(仅减少引用计数)
        ilog("=== 6.2 Phase 1: call unload() ===");

        // 显示引用计数状态
        ilog("Before unload(), devices_module_ref refcount: ${count}", ("count", devices_module_ref.use_count()));
        ilog("Before unload(), network_module_ref refcount: ${count}", ("count", network_module_ref.use_count()));

        ilog("Calling module_manager.unload('mc.devices')...");
        module_manager.unload("mc.devices");

        // 显示引用计数状态
        ilog("After unload(), devices_module_ref refcount: ${count}", ("count", devices_module_ref.use_count()));

        // 验证模块管理器认为模块已卸载
        bool devices_still_loaded = module_manager.is_loaded("mc.devices");
        ilog("module manager status: ${status}", ("status", devices_still_loaded ? "loaded" : "not loaded"));

        // 但是模块引用仍然可用,因为我们持有 module_ptr
        if (devices_module_ref) {
            auto factory    = devices_module_ref->get_factory();
            auto sensor_obj = factory->try_create_object("Sensor");
            if (sensor_obj) {
                sensor_obj->invoke_method("setName", {mc::variant("after_unload_test")});
                auto name_result = sensor_obj->invoke_method("getName", {});
                ilog("✓ module reference still available: ${name}", ("name", name_result.as<std::string>()));
                ilog("✓ verification succeeded: after phase-1 unload, modules holding references remain usable");
            }
        }

        // 6.3 释放 module_ptr - 第二阶段卸载(真正卸载动态库)
        ilog("=== 6.3 Phase 2: release module_ptr ref ===");

        ilog("Releasing devices_module_ref...");
        ilog("Refcount before release: ${count}", ("count", devices_module_ref.use_count()));
        ilog("Watch console output; expect '[DEVICES MODULE] shared library actually unloaded!'");

        // 显式释放引用
        // TODO:: 目前可以确定这个引用销毁后,内部会调用 dlclose 卸载动态库,并且 dlopen/dlcose 的调用次数也是配对的,
        // 但不知道什么原因动态库的 module_unload_detector 并没有被调用,而是直到整个进程退出才调用,以后再说吧
        devices_module_ref.reset();

        // 强制刷新输出缓冲区
        std::cout.flush();

        ilog("devices_module_ref released");

        ilog("Releasing network_module_ref...");
        ilog("Refcount before release: ${count}", ("count", network_module_ref.use_count()));
        ilog("Watch console output; expect '[NETWORK MODULE] shared library actually unloaded!'");

        network_module_ref.reset(); // 显式释放引用

        // 强制刷新输出缓冲区
        std::cout.flush();

        ilog("network_module_ref already released");

        // 6.4 验证真正的重新加载
        ilog("=== 6.4 Verify actual reload ===");

        // 等待一下确保析构完成
        std::this_thread::sleep_for(std::chrono::milliseconds(100));

        ilog("Reloading devices module...");
        ilog("Watch console output; expect new '[DEVICES MODULE] module loaded'");
        auto reloaded_devices = mc::load_module("mc.devices");

        if (reloaded_devices) {
            ilog("✓ verification succeeded: module was actually reloaded");
            ilog("  Watch console module load/unload messages to verify the actual unload");

            // 测试重新加载的模块功能
            auto factory    = reloaded_devices->get_factory();
            auto sensor_obj = factory->try_create_object("Sensor");
            if (sensor_obj) {
                sensor_obj->invoke_method("setName", {mc::variant("reloaded_after_real_unload")});
                auto name_result = sensor_obj->invoke_method("getName", {});
                ilog("✓ reloaded module works: ${name}", ("name", name_result.as<std::string>()));
            }
        } else {
            elog("✗ reload failed");
            return false;
        }

        // 6.5 清理其他模块
        ilog("=== 6.5 Clean up other modules ===");

        // 清理 protocol 和 database 模块
        module_manager.unload("mc.protocol");
        module_manager.unload("mc.test.database");

        // 这些模块没有持有额外引用,所以应该立即卸载
        // 但它们没有卸载检测器,所以不会有输出

        // 6.6 最终状态检查
        ilog("=== 6.6 Final state check ===");
        std::vector<std::string> all_modules = {"mc.devices", "mc.network", "mc.protocol", "mc.test.database"};
        for (const auto& module_name : all_modules) {
            bool is_loaded = module_manager.is_loaded(module_name);
            ilog("  ${name}: ${status}", ("name", module_name)("status", is_loaded ? "loaded" : "not loaded"));
        }

        ilog("=== Two-phase module unload verification done ===");
        ilog("✓ verified unload() is only a logical unload");
        ilog("✓ verified module holding module_ptr is still available");
        ilog("✓ verified the shared library is actually unloaded after all references are released");
        ilog("✓ verified reload actually reinitializes the module");

        return true;
    } catch (const mc::exception& e) {
        elog("two-phase unload test failed: ${msg}", ("msg", e.what()));
        return false;
    } catch (const std::exception& e) {
        elog("two-phase unload test failed: ${msg}", ("msg", e.what()));
        return false;
    }
}

/**
 * @brief 演示模块系统
 */
int main()
{
    try {
        ilog("starting module loading demo");

        // 执行各个测试步骤
        bool success = true;

        // 1. 测试 devices 模块
        success &= test_devices_module();

        // 2. 测试 network 模块
        success &= test_network_module();

        // 3. 测试 protocol 模块
        success &= test_protocol_module();

        // 4. 测试 database 模块
        success &= test_database_module();

        // 5. 路径查找验证总结
        test_module_path_summary();

        // 6. 模块两阶段卸载机制验证
        success &= test_two_phase_unload();

        if (success) {
            ilog("all tests completed!");
            return 0;
        } else {
            elog("Some tests failed");
            return -1;
        }

    } catch (const mc::exception& e) {
        elog("exception: ${msg}", ("msg", e.what()));
        return -1;
    } catch (const std::exception& e) {
        elog("standard exception: ${msg}", ("msg", e.what()));
        return -1;
    }
}