from __future__ import annotations

import os
import subprocess
import time
import warnings
from dataclasses import replace
from typing import Any, Callable

import pytest

from popup_window import PopupWindow
from ui.alerts_tab import AlertsTab
from ui.view_model import AlertVM, AlertsTabVM, DashboardCallbacks


pytestmark = pytest.mark.skipif(
    os.environ.get("SYSTRAY_AI_GUI_TESTS") != "1",
    reason="run with tests/run_gui_tests.sh",
)


def _pump_events(
    gtk: Any, condition: Callable[[], bool], timeout_seconds: float = 2.0
) -> None:
    deadline = time.monotonic() + timeout_seconds
    while time.monotonic() < deadline:
        while gtk.events_pending():
            gtk.main_iteration_do(False)
        if condition():
            return
        time.sleep(0.01)
    raise AssertionError("GTK did not process the xdotool click")


def test_xdotool_dismissal_shrinks_live_popup() -> None:
    import gi

    warnings.filterwarnings(
        "ignore",
        message=r"GLib\.unix_signal_add_full is deprecated; use GLibUnix\.signal_add_full instead",
        category=gi.PyGIDeprecationWarning,
    )
    gi.require_version("Gtk", "3.0")
    from gi.repository import Gtk

    initialized, _argv = Gtk.init_check([])
    assert initialized
    dismissed: list[tuple[str, str, str]] = []
    alert = AlertVM(
        kind="broken",
        tool="codex",
        slug="personal",
        title_text="codex/personal auth expired",
        detail_text="health checks paused",
        action="repair",
        action_label="Repair…",
        action_slug=None,
    )
    empty_vm = AlertsTabVM(
        alerts=(), healthy_lines=(), empty_heading="All good", empty_detail=""
    )
    popup = PopupWindow(title="Systray AI GUI alert dismissal", gtk_module=Gtk)
    tab: AlertsTab

    def dismiss(kind: str, tool: str, slug: str) -> None:
        dismissed.append((kind, tool, slug))
        tab.update(empty_vm)
        popup.resize_to_content()

    callbacks = DashboardCallbacks(
        on_set_default=lambda _tool, _slug: None,
        on_reload=lambda _tool, _slug: None,
        on_repair=lambda _tool, _slug: None,
        on_rename=lambda _tool, _slug: None,
        on_remove=lambda _tool, _slug: None,
        on_add=lambda _tool: None,
        on_open_settings=lambda: None,
        on_set_limits=lambda _tool, _slug: None,
        on_tab_changed=lambda _tab_id: None,
        on_dismiss_alert=dismiss,
    )
    tab = AlertsTab(
        AlertsTabVM(
            alerts=(
                alert,
                replace(alert, slug="work", title_text="codex/work auth expired"),
                replace(alert, slug="team", title_text="codex/team auth expired"),
            ),
            healthy_lines=(),
            empty_heading="",
            empty_detail="",
        ),
        callbacks,
        gtk_module=Gtk,
    )
    popup.add(tab.widget)
    popup.show()
    _pump_events(Gtk, lambda: popup.window.get_window() is not None)
    initial_width, initial_height = popup.window.get_size()
    button = tab.banners[0].close_button
    translated = button.translate_coordinates(popup.window, 0, 0)
    assert translated is not None
    button_x, button_y = translated
    allocation = button.get_allocation()
    _success, origin_x, origin_y = popup.window.get_window().get_origin()
    subprocess.run(
        [
            "xdotool",
            "mousemove",
            "--sync",
            str(origin_x + button_x + allocation.width // 2),
            str(origin_y + button_y + allocation.height // 2),
            "click",
            "1",
        ],
        check=True,
    )
    _pump_events(Gtk, lambda: bool(dismissed))

    try:
        assert dismissed == [("broken", "codex", "personal")]
        assert popup.window.get_size()[0] <= initial_width
        assert popup.window.get_size()[1] < initial_height
    finally:
        popup.window.destroy()
