#include "device_bus/DeviceBus.h"

#include <QDir>
#include <QFileInfo>
#include <QJsonDocument>
#include <QSaveFile>

#include "device_bus/manager/DeviceBusManager.h"
#include "device_bus/monitor/DeviceMonitorService.h"
#include "device_bus/registry/DeviceRegistry.h"
#include "device_bus/tree/DeviceTreeModel.h"
#include "utils/logs/logging.h"

namespace softbus::device_bus {

class DeviceBus::Impl {
public:
  std::unique_ptr<DeviceBusManager> manager;
  std::unique_ptr<monitor::DeviceMonitorService> monitorService;
  std::unique_ptr<registry::DeviceRegistry> registry;
  std::shared_ptr<DeviceTreeModel> treeModel;
  QString configPath;
  bool deviceTreeDirty{false}; // 设备树是否脏了
};

DeviceBus &DeviceBus::instance() {
  static DeviceBus inst;
  return inst;
}

DeviceBus::DeviceBus() : d(new Impl()) {}

DeviceBus::~DeviceBus() {
  delete d;
  d = nullptr;
}

bool DeviceBus::initialize(const QJsonObject &rootConfig) {
  if (!d) {
    return false;
  }

  if (!d->treeModel) {
    d->treeModel = std::make_shared<DeviceTreeModel>();
  }
  if (!d->manager) {
    d->manager = std::make_unique<DeviceBusManager>();
  }
  if (!d->registry) {
    d->registry = std::make_unique<registry::DeviceRegistry>(d->treeModel);
  }
  d->manager->setDeviceTreeModel(d->treeModel);
  d->manager->setRegistry(d->registry.get());
  d->manager->setDirtyCallback([this]() { this->markDeviceTreeDirty(); });

  // 1) Load persisted config and initialize manager
  if (!d->manager->initialize(rootConfig)) {
    return false;
  }

  // 2) Start monitor service
  if (!d->monitorService) {
    d->monitorService = std::make_unique<monitor::DeviceMonitorService>(nullptr);
    d->monitorService->setRegistry(d->registry.get());
    d->monitorService->setDirtyCallback([this]() { this->markDeviceTreeDirty(); });
  }
  if (!d->monitorService->start()) {
    LOG_WARNING() << "DeviceBus: device monitor service start failed";
  }

  // 3) Initial snapshot scan (register existing devices)
  d->monitorService->initialScan();

  // 4) Reconcile runtime instances against latest tree model
  d->manager->reconcileFromTreeModel();
  return true;
}

void DeviceBus::shutdown() {
  if (!d) {
    return;
  }

  if (d->monitorService) {
    LOG_INFO() << "DeviceBus shutting down monitor service";
    d->monitorService->stop();
    d->monitorService.reset();
  }

  if (d->manager) {
    LOG_INFO() << "DeviceBus shutting down manager";
    d->manager->shutdown();
  }

  if (!d->deviceTreeDirty) {
    LOG_INFO() << "DeviceBus device tree dirty is false";
    return;
  }
  
  if (d->configPath.isEmpty() || !d->treeModel) {
    return;
  }

  const QFileInfo fi(d->configPath);
  const QString dirPath = fi.dir().absolutePath();
  LOG_INFO() << "DeviceBus: saving config to" << dirPath;
  if (!QDir().mkpath(dirPath)) {
    LOG_ERROR() << "DeviceBus: failed to create config dir" << dirPath;
    return;
  }

  const QJsonObject root = d->treeModel->toDaemonConfigRoot();
  const QByteArray bytes = QJsonDocument(root).toJson(QJsonDocument::Indented);

  QSaveFile out(d->configPath);
  if (!out.open(QIODevice::WriteOnly | QIODevice::Text)) {
    LOG_ERROR() << "DeviceBus: failed to open config for write:" << d->configPath;
    return;
  }
  if (out.write(bytes) != bytes.size()) {
    LOG_ERROR() << "DeviceBus: failed to write config:" << d->configPath;
    out.cancelWriting();
    return;
  }
  if (!out.commit()) {
    LOG_ERROR() << "DeviceBus: failed to commit config:" << d->configPath;
    return;
  }

  d->deviceTreeDirty = false;
}

void DeviceBus::setConfigPath(const QString& path) {
  if (!d) return;
  d->configPath = path;
}

QString DeviceBus::configPath() const {
  if (!d) return {};
  return d->configPath;
}

std::shared_ptr<DeviceTreeModel> DeviceBus::deviceTreeModel() const {
  if (!d) return {};
  return d->treeModel;
}

void DeviceBus::markDeviceTreeDirty() {
  if (!d) return;
  d->deviceTreeDirty = true;
}

} // namespace softbus::device_bus
