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

#include "stubext.h"
#include <gtest/gtest.h>

#include "mountcontroldbus.h"
#include "private/mountcontroldbus_p.h"
#include "mounthelpers/abstractmounthelper.h"
#include "service_mountcontrol_global.h"
#include "mounthelpers/cifsmounthelper.h"

#include <QFile>
#include <QDBusConnection>
#include <QVariantMap>

#include <DConfig>

SERVICEMOUNTCONTROL_USE_NAMESPACE
DCORE_USE_NAMESPACE

using RegisterObjectFuncPtr = bool (QDBusConnection::*)(const QString &, QObject *, QDBusConnection::RegisterOptions);

class MockMountHelper : public AbstractMountHelper
{
public:
    explicit MockMountHelper(QDBusContext *context)
        : AbstractMountHelper(context) { }

    QVariantMap mount(const QString &path, const QVariantMap &opts) override
    {
        mountCalled = true;
        lastMountPath = path;
        lastMountOpts = opts;
        return mockMountResult;
    }

    QVariantMap unmount(const QString &path, const QVariantMap &opts) override
    {
        unmountCalled = true;
        lastUnmountPath = path;
        lastUnmountOpts = opts;
        return mockUnmountResult;
    }

    // Test data
    bool mountCalled = false;
    bool unmountCalled = false;
    QString lastMountPath;
    QString lastUnmountPath;
    QVariantMap lastMountOpts;
    QVariantMap lastUnmountOpts;
    QVariantMap mockMountResult;
    QVariantMap mockUnmountResult;
};

class UT_MountControlDBus : public testing::Test
{
protected:
    virtual void SetUp() override
    {
        // Mock QFile::exists to return false (disable daemon mount is not present)
        stub.set_lamda(static_cast<bool (QFile::*)() const>(&QFile::exists), [](QFile *) {
            __DBG_STUB_INVOKE__
            return false;
        });

        // Mock DBus connection registration
        stub.set_lamda(static_cast<QDBusConnection (*)(QDBusConnection::BusType, const QString &)>(&QDBusConnection::connectToBus),
                       [](QDBusConnection::BusType, const QString &) {
                           __DBG_STUB_INVOKE__
                           return QDBusConnection::sessionBus();
                       });

        stub.set_lamda(static_cast<RegisterObjectFuncPtr>(&QDBusConnection::registerObject), [](QDBusConnection *, const QString &, QObject *, QDBusConnection::RegisterOptions) {
            __DBG_STUB_INVOKE__
            return true;
        });

        // Mock DConfig creation to return null (disable cifs mount)
        stub.set_lamda(static_cast<DConfig *(*)(const QString &, const QString &, const QString &, QObject *)>(&DConfig::create),
                       [](const QString &, const QString &, const QString &, QObject *) -> DConfig * {
                           __DBG_STUB_INVOKE__
                           return nullptr;
                       });

        mountControlDBus = new MountControlDBus("test.service");
    }

    virtual void TearDown() override
    {
        stub.clear();
        delete mountControlDBus;
    }

private:
    stub_ext::StubExt stub;
    MountControlDBus *mountControlDBus = nullptr;

protected:
    MountControlDBus *getDBus() { return mountControlDBus; }

    void addMockHelper(const QString &fsType, MockMountHelper *helper)
    {
        // Access private member through friend mechanism or reflection
        auto *d = mountControlDBus->d.data();
        d->mountHelpers.insert(fsType, helper);
        if (!d->supportedFS.contains(fsType)) {
            d->supportedFS.append(fsType);
        }
    }
};

TEST_F(UT_MountControlDBus, Constructor_DisableDaemonMountExists_DoesNotRegisterDBus)
{
    // Test constructor when disable daemon mount file exists
    stub.clear();

    // Mock QFile::exists to return true (disable daemon mount file exists)
    stub.set_lamda(static_cast<bool (QFile::*)() const>(&QFile::exists), [](QFile *) {
        __DBG_STUB_INVOKE__
        return true;
    });

    bool dbusRegistered = false;
    stub.set_lamda(static_cast<RegisterObjectFuncPtr>(&QDBusConnection::registerObject), [&dbusRegistered](QDBusConnection *, const QString &, QObject *, QDBusConnection::RegisterOptions) {
        __DBG_STUB_INVOKE__
        dbusRegistered = true;
        return true;
    });

    MountControlDBus testDBus("test.service");

    EXPECT_FALSE(dbusRegistered);
}

TEST_F(UT_MountControlDBus, SupportedFileSystems_ReturnsConfiguredSystems)
{
    // Test SupportedFileSystems returns the configured systems

    // Add some mock helpers to test
    MockMountHelper *cifsHelper = new MockMountHelper(nullptr);
    MockMountHelper *dlnfsHelper = new MockMountHelper(nullptr);

    addMockHelper("cifs", cifsHelper);
    addMockHelper("dlnfs", dlnfsHelper);

    QStringList result = getDBus()->SupportedFileSystems();

    EXPECT_TRUE(result.contains("cifs"));
    EXPECT_TRUE(result.contains("dlnfs"));
}

class UT_MountControlDBusPrivate : public testing::Test
{
protected:
    virtual void SetUp() override
    {
        // Mock QFile::exists to return false
        stub.set_lamda(static_cast<bool (QFile::*)() const>(&QFile::exists), [](QFile *) {
            __DBG_STUB_INVOKE__
            return false;
        });

        // Mock DBus connection registration
        stub.set_lamda(static_cast<QDBusConnection (*)(QDBusConnection::BusType, const QString &)>(&QDBusConnection::connectToBus),
                       [](QDBusConnection::BusType, const QString &) {
                           __DBG_STUB_INVOKE__
                           return QDBusConnection::sessionBus();
                       });

        stub.set_lamda(static_cast<RegisterObjectFuncPtr>(&QDBusConnection::registerObject), [](QDBusConnection *, const QString &, QObject *, QDBusConnection::RegisterOptions) {
            __DBG_STUB_INVOKE__
            return true;
        });

        mountControlDBus = new MountControlDBus("test.service");
    }

    virtual void TearDown() override
    {
        stub.clear();
        delete mountControlDBus;
    }

private:
    stub_ext::StubExt stub;
    MountControlDBus *mountControlDBus = nullptr;

protected:
    MountControlDBus *getDBus() { return mountControlDBus; }
};

TEST_F(UT_MountControlDBusPrivate, Constructor_CifsDisabled_DoesNotAddCifsHelper)
{
    // Test constructor when CIFS mount is disabled
    stub.clear();

    // Mock QFile::exists to return false
    stub.set_lamda(static_cast<bool (QFile::*)() const>(&QFile::exists), [](QFile *) {
        __DBG_STUB_INVOKE__
        return false;
    });

    // Mock DBus connection registration
    stub.set_lamda(static_cast<QDBusConnection (*)(QDBusConnection::BusType, const QString &)>(&QDBusConnection::connectToBus),
                   [](QDBusConnection::BusType, const QString &) {
                       __DBG_STUB_INVOKE__
                       return QDBusConnection::sessionBus();
                   });

    stub.set_lamda(static_cast<RegisterObjectFuncPtr>(&QDBusConnection::registerObject), [](QDBusConnection *, const QString &, QObject *, QDBusConnection::RegisterOptions) {
        __DBG_STUB_INVOKE__
        return true;
    });

    // Mock DConfig creation to return null (disable cifs mount)
    stub.set_lamda(static_cast<DConfig *(*)(const QString &, const QString &, const QString &, QObject *)>(&DConfig::create),
                   [](const QString &, const QString &, const QString &, QObject *) -> DConfig * {
                       __DBG_STUB_INVOKE__
                       return nullptr;
                   });

    MountControlDBus testDBus("test.service");
    QStringList supportedFS = testDBus.SupportedFileSystems();

    EXPECT_FALSE(supportedFS.contains("cifs"));
    EXPECT_TRUE(supportedFS.contains("dlnfs"));   // Should still have dlnfs
}

TEST_F(UT_MountControlDBusPrivate, Constructor_CifsEnabled_AddsCifsHelper)
{
    // Test constructor when CIFS mount is enabled
    stub.clear();

    // Mock QFile::exists to return false
    stub.set_lamda(static_cast<bool (QFile::*)() const>(&QFile::exists), [](QFile *) {
        __DBG_STUB_INVOKE__
        return false;
    });

    // Mock DBus connection registration
    stub.set_lamda(static_cast<QDBusConnection (*)(QDBusConnection::BusType, const QString &)>(&QDBusConnection::connectToBus),
                   [](QDBusConnection::BusType, const QString &) {
                       __DBG_STUB_INVOKE__
                       return QDBusConnection::sessionBus();
                   });

    stub.set_lamda(static_cast<RegisterObjectFuncPtr>(&QDBusConnection::registerObject), [](QDBusConnection *, const QString &, QObject *, QDBusConnection::RegisterOptions) {
        __DBG_STUB_INVOKE__
        return true;
    });

    // Create mock DConfig that enables CIFS mount
    static DConfig mockConfig("");
    stub.set_lamda(static_cast<DConfig *(*)(const QString &, const QString &, const QString &, QObject *)>(&DConfig::create),
                   [](const QString &, const QString &, const QString &, QObject *) -> DConfig * {
                       __DBG_STUB_INVOKE__
                       return &mockConfig;
                   });

    stub.set_lamda(&DConfig::value, [](DConfig *, const QString &key, const QVariant &) -> QVariant {
        __DBG_STUB_INVOKE__
        if (key == "enableCifsMount")
            return QVariant(true);
        return QVariant();
    });

    stub.set_lamda(static_cast<void (QObject::*)()>(&DConfig::deleteLater), [](QObject *) {
        __DBG_STUB_INVOKE__
    });

    // Mock CifsMountHelper::cleanMountPoint
    stub.set_lamda(&CifsMountHelper::cleanMountPoint, [](CifsMountHelper *) {
        __DBG_STUB_INVOKE__
    });

    MountControlDBus testDBus("test.service");
    QStringList supportedFS = testDBus.SupportedFileSystems();

    EXPECT_TRUE(supportedFS.contains("cifs"));
    EXPECT_TRUE(supportedFS.contains("dlnfs"));
}
