#include "device_bus/monitor/DeviceMonitorService.h"

#include <QJsonDocument>

#include "device_bus/registry/IDeviceRegistry.h"
#include "utils/logs/logging.h"

#if defined(__linux__)
#include "device_bus/monitor/UdevDeviceMonitor.h"
#include "device_bus/monitor/NetlinkDeviceMonitor.h"
#endif

#if defined(_WIN32)
#include "device_bus/monitor/WindowsDeviceMonitor.h"
#endif

namespace softbus::device_bus::monitor
{

DeviceMonitorService::DeviceMonitorService(QObject* parent)
    : QObject(parent)
{
#if defined(__linux__)
    m_monitors.emplace_back(std::make_unique<UdevDeviceMonitor>(this));
    m_monitors.emplace_back(std::make_unique<NetlinkDeviceMonitor>(this));
#elif defined(_WIN32)
    m_monitors.emplace_back(std::make_unique<WindowsDeviceMonitor>(this));
#endif

    for (auto& m : m_monitors) {
        m->setCallback([this](const DeviceEvent& ev) { onEvent(ev); });
    }
}

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

bool DeviceMonitorService::start()
{
    if (m_started) return true;

    bool ok = true;
    for (auto& m : m_monitors) {
        ok = m->start() && ok;
    }
    m_started = ok;
    return ok;
}

bool DeviceMonitorService::initialScan()
{
    bool any = false;
    for (auto& m : m_monitors) {
        const auto snapshot = m->snapshotExisting();
        for (const auto& ev : snapshot) {
            onEvent(ev);
            any = true;
        }
    }
    return any;
}

void DeviceMonitorService::stop()
{
    if (!m_started) return;
    for (auto& m : m_monitors) {
        m->stop();
    }
    m_started = false;
}

void DeviceMonitorService::setRegistry(softbus::device_bus::registry::IDeviceRegistry* registry)
{
    m_registry = registry;
}

void DeviceMonitorService::setDirtyCallback(std::function<void()> cb)
{
    m_dirtyCb = std::move(cb);
}

void DeviceMonitorService::onEvent(const DeviceEvent& ev)
{
    // De-dup (short window): suppress identical events bursts
    const QString key = QStringLiteral("%1|%2|%3|%4|%5|%6|%7|%8|%9")
                            .arg(toString(ev.type),
                                 toString(ev.action),
                                 ev.subsystem,
                                 ev.devnode,
                                 ev.props.value(QStringLiteral("SYSPATH")),
                                 ev.ifname,
                                 QString::number(ev.ifindex),
                                 ev.vid + ev.pid,
                                 ev.serial);

    const qint64 nowMs = QDateTime::currentMSecsSinceEpoch();
    const qint64 lastMs = m_lastEventMsByKey.value(key, -1);
    if (lastMs >= 0 && (nowMs - lastMs) < 800) {
        return;
    }
    m_lastEventMsByKey.insert(key, nowMs);

    if (m_registry) {
        bool changed = false;
        if (ev.action == DeviceEventAction::Add || ev.action == DeviceEventAction::Change) {
            changed = m_registry->upsertFromMonitorEvent(ev);
        } else if (ev.action == DeviceEventAction::Remove) {
            changed = m_registry->markOfflineFromMonitorEvent(ev);
        }
        if (changed && m_dirtyCb) {
            m_dirtyCb();
        }
    }

    // 第一版：仅日志
    LOG_INFO() << "DeviceMonitor event"
               << "type=" << toString(ev.type)
               << "action=" << toString(ev.action)
               << "subsystem=" << ev.subsystem
               << "devnode=" << ev.devnode
               << "ifname=" << ev.ifname
               << "ifindex=" << ev.ifindex
               << "linkUp=" << ev.linkUp
               << "vid=" << ev.vid
               << "pid=" << ev.pid
               << "serial=" << ev.serial
               << "path=" << ev.devicePath;
}

} // namespace softbus::device_bus::monitor

