#include "window_watcher.h"
#include "waylandinterface_gtk.h"
#include <cstdio>
#include <cstring>
#include <stdio.h>

WindowWatcher &WindowWatcher::getInstance() {
    static WindowWatcher instance;
    return instance;
}

void WindowWatcher::initialize(GdkWindow *gdk_window) {
    if (wayland_initialized_) {
        return;
    }

    if (!gdk_window) {
        return;
    }

#ifdef GDK_WINDOWING_WAYLAND
    gdk_display_ = gdk_window_get_display(gdk_window);
    if (!GDK_IS_WAYLAND_DISPLAY(gdk_display_)) {
        return;
    }

    wl_display_ = gdk_wayland_display_get_wl_display(gdk_display_);
    if (!wl_display_) {
        return;
    }

    initWindow(wl_display_);
    wayland_initialized_ = true;
#endif
}

void WindowWatcher::addWindow(const std::string &uuid,
                              struct ukui_window *window_handle) {
    std::lock_guard<std::mutex> lock(mutex_);

    auto window_info = std::make_shared<WindowInfo>();
    window_info->window_handle = window_handle;
    strncpy(window_info->uuid, uuid.c_str(), sizeof(window_info->uuid) - 1);
    window_info->uuid[sizeof(window_info->uuid) - 1] = '\0';
    window_info->is_active = 0;
    window_map_[window_handle] = window_info;
}

void WindowWatcher::removeWindow(struct ukui_window *window_handle) {
    std::lock_guard<std::mutex> lock(mutex_);

    auto it = window_map_.find(window_handle);
    if (it != window_map_.end()) {
        std::string uuid = it->second->uuid;
        window_map_.erase(it);
    }
}

void WindowWatcher::updateWindowGeometry(struct ukui_window *window_handle,
                                         int32_t x, int32_t y, uint32_t width,
                                         uint32_t height) {
    std::lock_guard<std::mutex> lock(mutex_);

    auto it = window_map_.find(window_handle);
    if (it != window_map_.end()) {
        it->second->x = x;
        it->second->y = y;
        it->second->width = width;
        it->second->height = height;
    }
}

void WindowWatcher::updateWindowState(struct ukui_window *window_handle,
                                      bool is_active) {
    std::lock_guard<std::mutex> lock(mutex_);

    auto it = window_map_.find(window_handle);
    if (it != window_map_.end()) {
        it->second->is_active = is_active ? 1 : 0;
    }
}

WindowGeometry WindowWatcher::activeWindowGeometry() const {
    std::lock_guard<std::mutex> lock(mutex_);
    for (const auto &pair : window_map_) {
        if (pair.second->is_active) {
            return {pair.second->x, pair.second->y, pair.second->width,
                    pair.second->height};
        }
    }
    return {0, 0, 0, 0};
}

void WindowWatcher::clearAllWindows() {
    std::lock_guard<std::mutex> lock(mutex_);
    window_map_.clear();
}

// C接口实现
extern "C" {
void *window_watcher_get_instance() { return &WindowWatcher::getInstance(); }

void initialize_window_watcher_from_gdk_window(GdkWindow *gdk_window) {
    WindowWatcher::getInstance().initialize(gdk_window);
}

struct WindowGeometry window_watcher_get_active_window_geometry() {
    return WindowWatcher::getInstance().activeWindowGeometry();
}

void window_watcher_add_window(const char *uuid,
                               struct ukui_window *window_handle) {
    WindowWatcher::getInstance().addWindow(std::string(uuid), window_handle);
}

void window_watcher_remove_window(struct ukui_window *window_handle) {
    WindowWatcher::getInstance().removeWindow(window_handle);
}

void window_watcher_update_geometry(struct ukui_window *window_handle,
                                    int32_t x, int32_t y, uint32_t width,
                                    uint32_t height) {
    WindowWatcher::getInstance().updateWindowGeometry(window_handle, x, y,
                                                      width, height);
}

void window_watcher_update_state(struct ukui_window *window_handle,
                                 int is_active) {
    WindowWatcher::getInstance().updateWindowState(window_handle,
                                                   is_active != 0);
}

void window_watcher_clear_all() {
    WindowWatcher::getInstance().clearAllWindows();
}
}
