"""Shared base for NexusOS popup menus — override_redirect window, no WM placement."""
# PyGObject (gi.repository) is dynamically generated and its API is Optional-heavy
# (e.g. Gdk.Display.get_default() is typed Display|None). These are fine at runtime,
# so silence the type-checker noise for this GTK desktop script.
# pyright: reportMissingModuleSource=false, reportOptionalMemberAccess=false, reportArgumentType=false, reportCallIssue=false, reportAttributeAccessIssue=false

import gi, fcntl, os, sys, signal, subprocess
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk, Gdk, GdkPixbuf, GLib

NEXUS_CSS = b"""
* { font-family: sans-serif; }

window {
    background-color: #2a1d33;
    color: #f2f2f2;
    border: 1px solid #4d3461;
    border-radius: 6px;
}

notebook {
    background-color: #2a1d33;
}
notebook > header {
    background-color: #1e1526;
    border-bottom: 1px solid #4d3461;
    border-radius: 6px 6px 0 0;
}
notebook > header > tabs > tab {
    color: #a8a8a8;
    padding: 6px 16px;
    border: none;
    background-color: transparent;
    border-bottom: 2px solid transparent;
}
notebook > header > tabs > tab:checked {
    color: #8cc63f;
    border-bottom: 2px solid #8cc63f;
}
notebook > header > tabs > tab:hover:not(:checked) {
    color: #f2f2f2;
    background-color: rgba(140,198,63,0.10);
}
notebook stack {
    background-color: #2a1d33;
}

treeview {
    background-color: #1e1526;
    color: #f2f2f2;
}
treeview:selected {
    background-color: #88008f;
    color: #ffffff;
}
treeview:hover {
    background-color: rgba(140,198,63,0.14);
}
treeview header button {
    background-color: #1e1526;
    color: #a8a8a8;
    border: none;
    border-bottom: 1px solid #4d3461;
    box-shadow: none;
}

label { color: #f2f2f2; }

button {
    background-color: #2e3236;
    color: #f2f2f2;
    border: 1px solid #3a3d41;
    border-radius: 4px;
    padding: 5px 14px;
    box-shadow: none;
    text-shadow: none;
    -gtk-icon-shadow: none;
}
button:hover {
    background-color: rgba(140,198,63,0.18);
    border-color: #8cc63f;
    color: #8cc63f;
}
button:active {
    background-color: #8cc63f;
    color: #0a0a00;
}

scale trough {
    background-color: #1e1526;
    border: 1px solid #4d3461;
    border-radius: 4px;
    min-height: 6px;
}
scale trough highlight {
    background-color: #8cc63f;
    border-radius: 4px;
}
scale slider {
    background-color: #8cc63f;
    border: none;
    border-radius: 50%;
    min-width: 16px;
    min-height: 16px;
}

separator {
    background-color: #4d3461;
    min-height: 1px;
}

scrolledwindow { background-color: #1e1526; }

.section-header {
    color: #a8a8a8;
    font-size: 0.8em;
    padding: 4px 8px 2px 8px;
}
.action-row {
    padding: 6px 12px;
    border-radius: 4px;
}
.action-row:hover {
    background-color: rgba(140,198,63,0.14);
    color: #8cc63f;
}
.dim { color: #a8a8a8; }
"""


def apply_css():
    provider = Gtk.CssProvider()
    provider.load_from_data(NEXUS_CSS)
    Gtk.StyleContext.add_provider_for_screen(
        Gdk.Screen.get_default(),
        provider,
        Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION,
    )


def make_popup_window(width, height):
    """Create an override_redirect popup window — bypasses WM placement entirely."""
    win = Gtk.Window(type=Gtk.WindowType.POPUP)
    win.set_type_hint(Gdk.WindowTypeHint.POPUP_MENU)
    win.set_decorated(False)
    win.set_skip_taskbar_hint(True)
    win.set_skip_pager_hint(True)
    win.set_keep_above(True)
    win.set_default_size(width, height)
    win.set_resizable(False)

    win.connect('key-press-event', lambda w, e: w.destroy() if e.keyval == Gdk.KEY_Escape else None)

    def on_button_press(w, event):
        wx, wy = w.get_position()
        ww = w.get_allocated_width()
        wh = w.get_allocated_height()
        rx, ry = int(event.x_root), int(event.y_root)
        if rx < wx or rx >= wx + ww or ry < wy or ry >= wy + wh:
            w.destroy()
        return False
    win.connect('button-press-event', on_button_press)

    def on_map(w, _event):
        def do_grab():
            gdk_win = w.get_window()
            if gdk_win:
                seat = Gdk.Display.get_default().get_default_seat()
                seat.grab(gdk_win, Gdk.SeatCapabilities.ALL, True, None, None, None)
            return False  # don't repeat
        GLib.timeout_add(150, do_grab)
        return False
    win.connect('map-event', on_map)

    def on_destroy(w):
        Gdk.Display.get_default().get_default_seat().ungrab()
    win.connect('destroy', on_destroy)

    return win


def get_mouse_position():
    display = Gdk.Display.get_default()
    seat = display.get_default_seat()
    _, x, y = seat.get_pointer().get_position()
    return x, y


def get_panel_bottom():
    """Return y-coordinate just below the top panel via _NET_WORKAREA."""
    try:
        out = subprocess.check_output(
            ['xprop', '-root', '_NET_WORKAREA'],
            text=True, stderr=subprocess.DEVNULL
        )
        nums = [int(n.strip()) for n in out.split('=')[1].split(',')]
        return nums[1]  # workarea y = where usable area begins (= panel height)
    except Exception:
        return 40


def position_window(win, width, height):
    """Position popup just below the panel, horizontally centered on click."""
    mx, _ = get_mouse_position()
    screen = Gdk.Screen.get_default()
    sw, sh = screen.get_width(), screen.get_height()

    panel_bottom = get_panel_bottom()
    x = mx - width // 2
    y = panel_bottom + 2

    x = max(4, min(x, sw - width - 4))
    if height > 0:
        y = min(y, sh - height - 4)

    win.move(x, y)


def single_instance(lockfile, pidfile):
    """flock-based single instance. Returns lock_fd on success, exits on collision."""
    fd = open(lockfile, 'w')
    try:
        fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
    except IOError:
        try:
            with open(pidfile) as f:
                os.kill(int(f.read().strip()), signal.SIGTERM)
        except Exception:
            pass
        sys.exit(0)
    with open(pidfile, 'w') as f:
        f.write(str(os.getpid()))
    return fd


def load_icon(path, size=16):
    try:
        return GdkPixbuf.Pixbuf.new_from_file_at_size(path, size, size)
    except Exception:
        return None
