#include "plasma-shell-manager.h"

#include <QApplication>

#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/registry.h>

#include <KWayland/Client/surface.h>
#include <unistd.h>
#include <QDebug>

static PlasmaShellManager* global_instance = nullptr;

PlasmaShellManager *PlasmaShellManager::getInstance()
{
    if (!global_instance)
    {
        global_instance = new PlasmaShellManager;
        qDebug() << "Here create instance...";
    }
    qDebug() << "Return instance";
    return global_instance;
}

bool PlasmaShellManager::setAppWindowActive()
{
    if (!supportPlasmaWindowManagement())
        return false;

    m_appWindow->requestActivate();
    return true;
}

bool PlasmaShellManager::setAppWindowKeepAbove(bool keep)
{
    if (!supportPlasmaWindowManagement())
    {
        qDebug() << "false";
        return false;
    }
    if(keep != m_appWindow->isKeepAbove()) {
        qDebug() << "to keep above";
        m_appWindow->requestToggleKeepAbove();
    }
    return true;
}

bool PlasmaShellManager::setMaximized(QWindow *window)
{
    if (!supportShell())
        return false;

    auto surface = KWayland::Client::Surface::fromWindow(window);
    if (!surface)
        return false;

    auto shellSurface = m_shell->createSurface(surface, window);
    if (!shellSurface)
        return false;

    shellSurface->setMaximized();
    return true;
}

bool PlasmaShellManager::setRole(QWindow *window, KWayland::Client::PlasmaShellSurface::Role role)
{
    if (!supportPlasmaShell())
        return false;

    auto surface = KWayland::Client::Surface::fromWindow(window);
    if (!surface)
        return false;

    auto plasmaShellSurface = m_plasmaShell->createSurface(surface, window);
    if (!plasmaShellSurface)
        return false;

    plasmaShellSurface->setRole(role);
    return true;
}

bool PlasmaShellManager::setPos(QWindow *window, const QPoint &pos)
{
    if (!supportPlasmaShell())
        return false;

    auto surface = KWayland::Client::Surface::fromWindow(window);
    if (!surface)
        return false;

    auto plasmaShellSurface = m_plasmaShell->createSurface(surface, window);
    if (!plasmaShellSurface)
        return false;

    plasmaShellSurface->setPosition(pos);
    return true;
}

bool PlasmaShellManager::supportPlasmaShell()
{
    return m_plasmaShell;
}

bool PlasmaShellManager::supportShell()
{
    return m_shell;
}

bool PlasmaShellManager::supportPlasmaWindowManagement()
{
    return m_windowManager && m_appWindow;
}

PlasmaShellManager::PlasmaShellManager(QObject *parent) : QObject(parent)
{
    auto connection = KWayland::Client::ConnectionThread::fromApplication(qApp);
    auto registry = new KWayland::Client::Registry(this);
    registry->create(connection->display());

    connect(registry, &KWayland::Client::Registry::plasmaShellAnnounced, this, [=](){
        qDebug() << "plasmaShellAnnounced...";
        const auto interface = registry->interface(KWayland::Client::Registry::Interface::PlasmaShell);
        if (interface.name != 0) {
            qDebug() << "createPlasmaShell...";
            m_plasmaShell = registry->createPlasmaShell(interface.name, interface.version, this);
        }
    });

    connect(registry, &KWayland::Client::Registry::plasmaWindowManagementAnnounced, this, [=](){
        qDebug() << "plasmaWindowManagementAnnounced";
        const auto interface = registry->interface(KWayland::Client::Registry::Interface::PlasmaWindowManagement);
        if (interface.name != 0) {
            qDebug() << "createPlasmaWindowManagement";
            m_windowManager = registry->createPlasmaWindowManagement(interface.name, interface.version, this);
        }
        if(m_windowManager) {
            connect(m_windowManager, &KWayland::Client::PlasmaWindowManagement::windowCreated,
                [this](KWayland::Client::PlasmaWindow *window) {
                qDebug()<< "PlasmaWindow...";
                if (window->pid() == getpid()) {
                    if(isFirstCreate) {
                        isFirstCreate = false;
                        m_appWindow = window;
                   }
               }
            });
        }
    });

    connect(registry, &KWayland::Client::Registry::shellAnnounced, this, [=](){
        const auto interface = registry->interface(KWayland::Client::Registry::Interface::Shell);
        if (interface.name != 0) {
            m_shell = registry->createShell(interface.name, interface.version, this);
        }
    });

    registry->setup();
    connection->roundtrip();
}
