#pragma once

// #include "ukui-window-management.h"
#include "plasma-window-management.h"
#include "ukui-startup-v1.h"
#include "ukui-startup-v2.h"

#include <atomic>

#include <QThread>

class WaylandDisplay;

WaylandDisplay *waylandDisplay();

struct plasma_window
{
    org_kde_plasma_window *window;
    std::string uuid;
    std::string title;
    std::string appId;
    uint64_t pid;
    uint32_t state;
};

class WaylandDisplay : public QThread
{
    Q_OBJECT
public:
    WaylandDisplay();
    ~WaylandDisplay();

    plasma_window *getWindowByUuid(const std::string &uuid);
    std::unordered_map<std::string, plasma_window *> getWindows();
    void avtivateWindow(const std::string &uuid);

    // 基于ukui_startup_v1协议，wlcom高版本可能不再支持
    void setStartupGeometryForApp(int pid, int x, int y, int width, int height);

    // ukui_startup_management_v2
    void createStartupInfoForAppId(const std::string &app_id, int x, int y, int width, int height);
    void setPidForStartupInfoV2(const std::string &app_id, int pid);
    void setStartupGeometryForStartupInfoV2(const std::string &app_id, int x, int y, int width, int height);
    void finishSetupInfoV2(const std::string &app_id);

Q_SIGNALS:
    void windowAdded(const std::string &uuid);
    void windowRemoved(const std::string &uuid);
    void windowTitleChanged(const std::string &uuid, const std::string &title);
    void windowAppIdChanged(const std::string &uuid, const std::string &appId);
    void windowPidChanged(const std::string &uuid, uint64_t pid);
    void windowStateChanged(const std::string &uuid, uint32_t state);

protected:
    void run() override;

private:
    static wl_registry_listener m_registryListener;
    static void handle_global(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version);
    static void handle_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name);

    static org_kde_plasma_window_management_listener m_plasmaWindowManagementListener;
    static void handle_show_desktop_changed(void *data, struct org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t state);
    static void handle_window(void *data, struct org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t id);
    static void handle_stacking_order_changed(void *data, struct org_kde_plasma_window_management *org_kde_plasma_window_management, struct wl_array *ids);
    static void handle_stacking_order_uuid_changed(void *data, struct org_kde_plasma_window_management *org_kde_plasma_window_management, const char *uuids);
    static void handle_window_with_uuid(void *data, struct org_kde_plasma_window_management *org_kde_plasma_window_management, uint32_t id, const char *uuid);
    static void handle_stacking_order_changed_2(void *data, struct org_kde_plasma_window_management *org_kde_plasma_window_management);

    static org_kde_plasma_window_listener m_plasmaWindowListener;
    static void handle_title_changed(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *title);
    static void handle_app_id_changed(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *app_id);
    static void handle_state_changed(void *data, struct org_kde_plasma_window *org_kde_plasma_window, uint32_t flags);
    static void handle_virtual_desktop_changed(void *data, struct org_kde_plasma_window *org_kde_plasma_window, int32_t number);
    static void handle_themed_icon_name_changed(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *name);
    static void handle_unmapped(void *data, struct org_kde_plasma_window *org_kde_plasma_window);
    static void handle_initial_state(void *data, struct org_kde_plasma_window *org_kde_plasma_window);
    static void handle_parent_window(void *data, struct org_kde_plasma_window *org_kde_plasma_window, struct org_kde_plasma_window *parent);
    static void handle_geometry(void *data, struct org_kde_plasma_window *org_kde_plasma_window, int32_t x, int32_t y, uint32_t width, uint32_t height);
    static void handle_icon_changed(void *data, struct org_kde_plasma_window *org_kde_plasma_window);
    static void handle_pid_changed(void *data, struct org_kde_plasma_window *org_kde_plasma_window, uint32_t pid);
    static void handle_virtual_desktop_entered(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *id);
    static void handle_virtual_desktop_left(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *is);
    static void handle_application_menu(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *service_name, const char *object_path);
    static void handle_activity_entered(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *id);
    static void handle_activity_left(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *id);
    static void handle_resource_name_changed(void *data, struct org_kde_plasma_window *org_kde_plasma_window, const char *resource_name);
    static void handle_client_geometry(void *data, struct org_kde_plasma_window *org_kde_plasma_window, int32_t x, int32_t y, uint32_t width, uint32_t height);

    wl_display *m_display = nullptr;
    wl_registry *m_registry = nullptr;

    std::atomic<bool> m_stopEventQueueThread = false;

    // Wayland interfaces
    org_kde_plasma_window_management *m_plasmaWindowManagement = nullptr;
    // wayland::ukui_window_management_t m_ukuiWindowManagement;

    std::unordered_map<std::string, plasma_window *> m_windows;

    ukui_startup_management_v1 *m_startupManagement = nullptr;
    ukui_startup_management_v2 *m_startupManagementV2 = nullptr;
    std::unordered_map<std::string, ukui_startup_info_v2 *> m_startupInfoMap;

    bool connectToWayland();
    void disconnectWaylandDisplay();
    void initWaylandConnections();
    void readEventQueue();

    friend WaylandDisplay *waylandDisplay();
};