# SPDX-FileCopyrightText: 2022-2025 Nicotine+ Contributors
# SPDX-License-Identifier: GPL-3.0-or-later

import os
import sys

from gi.repository import Gtk

from pynicotine.gtkgui.application import GTK_API_VERSION
from pynicotine.gtkgui.application import LIBADWAITA_API_VERSION


class Window:

    DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19
    DWMWA_USE_IMMERSIVE_DARK_MODE = 20

    active_dialogs = []  # Class variable keeping dialog objects alive
    activation_token = None

    def __init__(self, widget):

        self.widget = widget
        self._dark_mode_handler = None
        self._text_widget = None

        if GTK_API_VERSION == 3:
            return

        self.widget.connect("notify::focus-widget", self._on_focus_widget_changed)

        if sys.platform == "win32":
            widget.connect("realize", self._on_realize_win32)

            # Use dark window controls on Windows when requested
            if LIBADWAITA_API_VERSION:
                from gi.repository import Adw  # pylint: disable=no-name-in-module
                self._dark_mode_handler = Adw.StyleManager.get_default().connect(
                    "notify::dark", self._on_dark_mode_win32
                )

        elif sys.platform == "darwin":
            # Workaround for GTK 4 bug where tooltips restore minimized window on hover
            self.widget.connect("notify::suspended", self._on_suspended_darwin)

        elif os.environ.get("GDK_BACKEND") == "broadway":
            # Workaround for GTK 4 bug where broadwayd uses a lot of CPU after hiding window
            self.widget.connect("hide", self._on_hide_broadway)

    def _on_focus_widget_changed(self, *_args):

        focus_widget = self.widget.get_focus()

        if focus_widget is None:
            return

        popover = focus_widget.get_ancestor(Gtk.Popover)

        # Workaround for GTK 4 bug where broadwayd uses a lot of CPU after hiding popover
        if popover is not None and os.environ.get("GDK_BACKEND") == "broadway":
            popover.hide_handler_broadway = popover.connect_after("hide", self._on_popover_hide_broadway)

    def _on_popover_hide_broadway(self, popover):

        if popover.hide_handler_broadway is not None:
            popover.disconnect(popover.hide_handler_broadway)
            popover.hide_handler_broadway = None

        popover.unrealize()

    def _on_realize_win32(self, *_args):

        from ctypes import windll

        # Don't overlap taskbar when auto-hidden
        h_wnd = self.get_surface().get_handle()
        windll.user32.SetPropW(h_wnd, "NonRudeHWND", True)

        # Set dark window controls
        if LIBADWAITA_API_VERSION:
            from gi.repository import Adw  # pylint: disable=no-name-in-module
            self._on_dark_mode_win32(Adw.StyleManager.get_default())

    def _on_dark_mode_win32(self, style_manager, *_args):

        surface = self.get_surface()

        if surface is None:
            return

        h_wnd = surface.get_handle()

        if h_wnd is None:
            return

        from ctypes import byref, c_int, sizeof, windll

        value = c_int(int(style_manager.get_dark()))

        if not windll.dwmapi.DwmSetWindowAttribute(
            h_wnd, self.DWMWA_USE_IMMERSIVE_DARK_MODE, byref(value), sizeof(value)
        ):
            windll.dwmapi.DwmSetWindowAttribute(
                h_wnd, self.DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, byref(value), sizeof(value)
            )

    def _on_suspended_darwin(self, *_args):
        self.widget.set_can_target(not self.widget.is_suspended())

    def _on_hide_broadway(self, *_args):
        self.widget.unrealize()

    def get_surface(self):

        if GTK_API_VERSION >= 4:
            return self.widget.get_surface()

        return self.widget.get_window()

    def get_width(self):

        if GTK_API_VERSION >= 4:
            return self.widget.get_width()

        width, _height = self.widget.get_size()
        return width

    def get_height(self):

        if GTK_API_VERSION >= 4:
            return self.widget.get_height()

        _width, height = self.widget.get_size()
        return height

    def get_position(self):

        if GTK_API_VERSION >= 4:
            return None

        return self.widget.get_position()

    def is_active(self):
        return self.widget.is_active()

    def is_maximized(self):
        return self.widget.is_maximized()

    def is_visible(self):
        return self.widget.get_visible()

    def set_title(self, title):
        self.widget.set_title(title)

    def maximize(self):
        self.widget.maximize()

    def unmaximize(self):
        self.widget.unmaximize()

    def present(self):

        if self.activation_token is not None:
            # Set XDG activation token if provided by tray icon
            self.widget.set_startup_id(self.activation_token)

        self.widget.present()

    def hide(self):
        self.widget.set_visible(False)

    def close(self, *_args):
        self.widget.close()

    def destroy(self):

        if self._dark_mode_handler is not None:
            from gi.repository import Adw  # pylint: disable=no-name-in-module
            Adw.StyleManager.get_default().disconnect(self._dark_mode_handler)

        self.widget.destroy()
        self.__dict__.clear()
