// SPDX-FileCopyrightText: 2022 - 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#include "burn.h"
#include "menus/sendtodiscmenuscene.h"
#include "utils/discstatemanager.h"
#include "utils/burnhelper.h"
#include "utils/burnsignalmanager.h"
#include "events/burneventreceiver.h"

#include "plugins/common/dfmplugin-menu/menu_eventinterface_helper.h"

#include <dfm-base/dfm_global_defines.h>
#include <dfm-base/dfm_event_defines.h>
#include <dfm-base/base/device/devicemanager.h>
#include <dfm-base/base/device/deviceutils.h>
#include <dfm-base/base/configs/dconfig/dconfigmanager.h>
#include <dfm-base/dbusservice/global_server_defines.h>
#include <dfm-base/dbusservice/opticalshareproxy.h>

#include <QWidget>
#include <QTimer>


DFMBASE_USE_NAMESPACE
namespace dfmplugin_burn {

DFM_LOG_REGISTER_CATEGORY(DPBURN_NAMESPACE)

static constexpr char kCurrentEventSpace[] { DPF_MACRO_TO_STR(DPBURN_NAMESPACE) };

namespace {

void clearStaleBurnStates()
{
    // On session bus, the daemon runs as the current user, so all stored
    // burn states belong to this user. Clear all stale states from the
    // previous session on startup.
    const auto states = OpticalShareProxy::instance().burnStates();
    for (auto iter = states.cbegin(); iter != states.cend(); ++iter) {
        OpticalShareProxy::instance().clearBurnState(iter.key());
    }
}

}   // namespace

void Burn::initialize()
{
    bindEvents();

    dpfSignalDispatcher->installEventFilter(GlobalEventType::kChangeCurrentUrl, this, &Burn::changeUrlEventFilter);
}

bool Burn::start()
{
    fmDebug() << "[Burn::start] Begin";

    dfmplugin_menu_util::menuSceneRegisterScene(SendToDiscMenuCreator::name(), new SendToDiscMenuCreator);
    bindScene("ShareMenu");

    DiscStateManager::instance()->initilaize();

    clearStaleBurnStates();
    connect(&OpticalShareProxy::instance(), &OpticalShareProxy::burnStateChanged,
            this, &Burn::onPersistenceDataChanged, Qt::DirectConnection);

    fmDebug() << "[Burn::start] Calling startOpticalDiscScan...";
    DevMngIns->startOpticalDiscScan();
    fmInfo() << "[Burn::start] startOpticalDiscScan returned";

    QString err;
    auto ret = DConfigManager::instance()->addConfig("org.deepin.dde.file-manager.burn", &err);
    if (!ret)
        fmWarning() << "create dconfig failed: " << err;

    return true;
}

void Burn::bindScene(const QString &parentScene)
{
    if (dfmplugin_menu_util::menuSceneContains(parentScene)) {
        dfmplugin_menu_util::menuSceneBind(SendToDiscMenuCreator::name(), parentScene);
    } else {
        waitToBind << parentScene;
        if (!eventSubscribed)
            eventSubscribed = dpfSignalDispatcher->subscribe("dfmplugin_menu", "signal_MenuScene_SceneAdded", this, &Burn::bindSceneOnAdded);
    }
}

void Burn::bindSceneOnAdded(const QString &newScene)
{
    if (waitToBind.contains(newScene)) {
        waitToBind.remove(newScene);
        if (waitToBind.isEmpty())
            eventSubscribed = !dpfSignalDispatcher->unsubscribe("dfmplugin_menu", "signal_MenuScene_SceneAdded", this, &Burn::bindSceneOnAdded);
        bindScene(newScene);
    }
}

void Burn::bindEvents()
{
    dpfSlotChannel->connect(kCurrentEventSpace, "slot_BurnDialog_Show", BurnEventReceiver::instance(), &BurnEventReceiver::handleShowBurnDlg);
    dpfSlotChannel->connect(kCurrentEventSpace, "slot_DumpISODialog_Show", BurnEventReceiver::instance(), &BurnEventReceiver::handleShowDumpISODlg);
    dpfSlotChannel->connect(kCurrentEventSpace, "slot_Erase", BurnEventReceiver::instance(), &BurnEventReceiver::handleErase);
    dpfSlotChannel->connect(kCurrentEventSpace, "slot_PasteTo", BurnEventReceiver::instance(), &BurnEventReceiver::handlePasteTo);
    dpfSlotChannel->connect(kCurrentEventSpace, "slot_MountImage", BurnEventReceiver::instance(), &BurnEventReceiver::handleMountImage);

    dpfSignalDispatcher->subscribe(GlobalEventType::kCopyResult, BurnEventReceiver::instance(), &BurnEventReceiver::handleCopyFilesResult);
    dpfSignalDispatcher->subscribe(GlobalEventType::kCutFileResult, BurnEventReceiver::instance(), &BurnEventReceiver::handleFileCutResult);
    dpfSignalDispatcher->subscribe(GlobalEventType::kDeleteFilesResult, BurnEventReceiver::instance(), &BurnEventReceiver::handleFileRemoveResult);
    dpfSignalDispatcher->subscribe(GlobalEventType::kRenameFileResult, BurnEventReceiver::instance(), &BurnEventReceiver::handleFileRenameResult);
}

bool Burn::changeUrlEventFilter(quint64 windowId, const QUrl &url)
{
    Q_UNUSED(windowId);
    if (url.scheme() == Global::Scheme::kBurn) {
        const auto &dev { BurnHelper::burnDestDevice(url) };
        if (DeviceUtils::isWorkingOpticalDiscDev(dev)) {
            emit BurnSignalManager::instance()->activeTaskDialog();
            return true;
        }
    }
    return false;
}

void Burn::onPersistenceDataChanged(const QString &key, const QVariantMap &value)
{
    fmInfo() << "Burn working state changed: " << key << value;
    auto id { value[GlobalServerDefines::OpticalShareField::kId].toString() };
    if (id.isEmpty())
        id = DeviceUtils::getBlockDeviceId(key);
    auto &&working { value[GlobalServerDefines::OpticalShareField::kWorking].toBool() };
    emit DevMngIns->opticalDiscWorkStateChanged(id, key, working);
}

}   // namespace dfmplugin_burn
