#include <softbus_daemon/core/CoreService.h>

#include <softbus_command/CommandContext.h>
#include <softbus_opcua/UaAddressSpaceBuilder.h>
#include <softbus_opcua/UaEventBridge.h>
#include <softbus_opcua/UaMethodBinder.h>
#include <softbus_opcua/UaModelBinder.h>
#include <softbus_opcua/UaServerEngine.h>

#include <softbus_core/identity/DeviceIdentity.h>
#include <softbus_core/logging/Logger.h>
#include <softbus_core/platform/PlatformSignal.h>

#ifdef SOFTBUS_PLATFORM_WINDOWS
#include <windows.h>
#endif

#include <filesystem>
#include <nlohmann/json.hpp>
#include <thread>
#include <vector>

namespace softbus::daemon {

namespace fs = std::filesystem;

namespace {

#ifdef SOFTBUS_PLATFORM_WINDOWS
std::vector<std::string> pluginFileNames(const std::string& pluginName)
{
    return {pluginName + ".dll"};
}
#else
std::vector<std::string> pluginFileNames(const std::string& pluginName)
{
    return {"lib" + pluginName + ".so", pluginName + ".so"};
}
#endif

std::string findPluginInDir(const fs::path& dir, const std::string& pluginName)
{
    if (!fs::exists(dir)) {
        return {};
    }
    for (const auto& fileName : pluginFileNames(pluginName)) {
        const fs::path candidate = dir / fileName;
        if (fs::exists(candidate)) {
            return fs::absolute(candidate).string();
        }
    }
    return {};
}

std::string commandResultJson(const softbus::command::CommandContext& ctx)
{
    nlohmann::json j;
    j["success"] = ctx.state == softbus::command::CommandState::Succeeded;
    j["requestId"] = ctx.requestId;
    j["state"] = softbus::command::commandStateToString(ctx.state);
    if (!ctx.error.empty()) {
        j["error"] = ctx.error;
    }
    if (ctx.executedValue != 0.0) {
        j["executedValue"] = ctx.executedValue;
    }
    return j.dump();
}

} // namespace

CoreService::CoreService()
    : commandService_(&registry_)
{
}

CoreService::~CoreService()
{
    stop();
}

std::string CoreService::resolvePluginPath(const std::string& pluginName,
                                           const std::string& profilePath) const
{
#ifdef SOFTBUS_PLATFORM_WINDOWS
    char exePath[MAX_PATH]{};
    GetModuleFileNameA(nullptr, exePath, MAX_PATH);
    const fs::path exeDir = fs::path(exePath).parent_path();
#else
    const fs::path exeDir = fs::current_path();
#endif

    const fs::path profileDir = fs::path(profilePath).parent_path();
    const fs::path cwd = fs::current_path();

    const fs::path searchDirs[] = {
        profileDir / "lib",
        cwd / "config" / "lib",
        exeDir,
        exeDir / ".." / "lib",
        cwd / "build" / "lib",
        fs::path("build") / "lib",
        cwd / "lib",
        cwd
    };

    for (const auto& dir : searchDirs) {
        if (const std::string found = findPluginInDir(dir, pluginName); !found.empty()) {
            return found;
        }
    }
    return fs::absolute(profileDir / "lib" / pluginFileNames(pluginName).front()).string();
}
//  主函数启动入口
//  profilePath: 配置文件路径
//  pointTablePath: 点表文件路径
//  return: 是否启动成功

bool CoreService::start(const std::string& profilePath, const std::string& pointTablePath)
{
    // 加载配置文件 
    if (!profile_.loadFromFile(profilePath)) {
        SB_LOG_ERROR("CoreService", "Failed to load profile: ", profilePath);
        return false;
    }

    const fs::path configDir = fs::path(pointTablePath).parent_path();
    // 加载主题规则文件
    registry_.loadTopicRules((configDir / "topic_rule.json").string());
    if (!registry_.loadPointTable(pointTablePath)) {
        SB_LOG_ERROR("CoreService", "Failed to load point table: ", pointTablePath);
        return false;
    }
    model_ = registry_.tree();

    const std::string pluginPath = resolvePluginPath(profile_.plugins.modbus, profilePath);
    if (!modbusPlugin_.load(pluginPath)) {
        SB_LOG_ERROR("CoreService", "Failed to load modbus plugin: ", pluginPath);
        return false;
    }
    // 加载点表文件
    auto& bus = softbus::bus::Bus::instance();
    // 将消息总线绑定到命令服务、存储服务和心跳监控服务
    commandService_.attachBus(&bus);
    storageService_.attachBus(&bus);
    heartbeatMonitor_.attachBus(&bus);

    // 创建OPC UA安全配置
    softbus::opcua::SecurityConfig security;
    security.enableTls = profile_.security.tlsEnabled;
    security.certPath = profile_.security.certPath;
    security.keyPath = profile_.security.keyPath;

    // 创建OPC UA服务引擎
    uaEngine_ = std::make_unique<softbus::opcua::UaServerEngine>();
    // 启动OPC UA服务
    if (!uaEngine_->start(profile_.opcua.port, profile_.opcua.applicationName, security)) {
        return false;
    }

    // 创建OPC UA模型绑定器
    uaBinder_ = std::make_unique<softbus::opcua::UaModelBinder>(uaEngine_->nativeServer());
    // 创建OPC UA方法绑定器
    uaMethodBinder_ = std::make_unique<softbus::opcua::UaMethodBinder>(uaEngine_->nativeServer());
    // 创建OPC UA事件桥接器
    uaEventBridge_ = std::make_unique<softbus::opcua::UaEventBridge>(uaEngine_->nativeServer());
    // 将消息总线绑定到OPC UA模型绑定器、OPC UA方法绑定器和OPC UA事件桥接器
    uaBinder_->attachBus(&bus);
    uaEventBridge_->attachBus(&bus);

    // 创建OPC UA地址空间构建器
    softbus::opcua::UaAddressSpaceBuilder builder(uaEngine_->nativeServer());
    // 构建OPC UA地址空间
    if (!builder.buildFromModel(model_, uaBinder_.get())) {
        SB_LOG_ERROR("CoreService", "Failed to build OPC UA address space");
        return false;
    }

    // 创建数据处理管道
    pipeline_ = std::make_unique<softbus::pipeline::PipelineEngine>(
        &modbusPlugin_, uaBinder_.get(), &registry_);
    pipeline_->attachBus(&bus);
    // 创建TCP上行监听服务器
    uplink_ = std::make_unique<softbus::transport::TcpUplinkServer>(
        io_, profile_.uplink.listenHost, profile_.uplink.listenPort);
    // 将消息总线绑定到TCP上行监听服务器
    transportBridge_.attach(&bus, uplink_.get());
    // 绑定OPC UA方法执行命令回调
    // 将OPC UA方法执行命令回调绑定到消息总线
    uaMethodBinder_->bindExecuteCommand([this](const softbus::api::ExecuteCommand& cmd) {
        const auto ctx = commandService_.submit(cmd, true);
        return commandResultJson(ctx);
    });
    
    uplink_->start();
    ioThread_ = std::thread([this]() { io_.run(); });
    running_ = true;
    SB_LOG_INFO("CoreService", "Daemon started (bus+registry+command pipeline)");
    return true;
}

void CoreService::stop()
{
    if (!running_) {
        return;
    }
    running_ = false;
    if (uplink_) {
        uplink_->stop();
    }
    io_.stop();
    if (ioThread_.joinable()) {
        ioThread_.join();
    }
    if (uaEngine_) {
        uaEngine_->stop();
    }
    modbusPlugin_.unload();
    SB_LOG_INFO("CoreService", "Daemon stopped");
}

void CoreService::run(bool selfTest)
{
    softbus::core::PlatformSignal::install(nullptr);

    bool selfTestDone = false;
    const auto selfTestStart = std::chrono::steady_clock::now();

    while (!softbus::core::PlatformSignal::shouldStop()) {
        if (uaEngine_) {
            uaEngine_->iterate();
        }
        heartbeatMonitor_.tick();
        if (selfTest && !selfTestDone
            && std::chrono::steady_clock::now() - selfTestStart > std::chrono::seconds(3)) {
            softbus::api::ExecuteCommand cmd;
            cmd.traceId = softbus::core::DeviceIdentity::generateTraceId();
            cmd.objectRef = "DemoSite/DemoSystem/DemoAsset/EdgeDevice_01/ValveOpening";
            cmd.command = "write";
            cmd.params = {{"value", 60.0}};
            const auto ctx = commandService_.submit(cmd, true);
            SB_LOG_INFO("CoreService", "self-test command state=",
                softbus::command::commandStateToString(ctx.state),
                " executedValue=", ctx.executedValue);
            selfTestDone = true;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    stop();
}

} // namespace softbus::daemon
