"""Full-width favourites row at the top of the app drawer.

Shows pinned apps (settings["favorites"], a list of .desktop entry ids). If nothing
is pinned yet it falls back to the most-frequently-launched apps. Pin/unpin from the
drawer grid via right-click / long-press.
"""

from __future__ import annotations

import gi

gi.require_version("Gtk", "4.0")
gi.require_version("AstalApps", "0.1")
from gi.repository import AstalApps, Gtk  # noqa: E402


def add_pin_gestures(widget: Gtk.Widget, on_toggle) -> None:
    """Wire right-click and long-press on `widget` to pin/unpin.

    Uses the CAPTURE phase and claims the sequence so the gesture fires reliably on a
    Gtk.Button (whose own primary-click gesture would otherwise swallow it) and does
    not also trigger the button's launch action."""
    def fire(gesture, *_a) -> None:
        on_toggle()
        gesture.set_state(Gtk.EventSequenceState.CLAIMED)

    rclick = Gtk.GestureClick(button=3)
    rclick.set_propagation_phase(Gtk.PropagationPhase.CAPTURE)
    rclick.connect("pressed", fire)
    widget.add_controller(rclick)

    longpress = Gtk.GestureLongPress()
    longpress.set_touch_only(False)
    longpress.set_propagation_phase(Gtk.PropagationPhase.CAPTURE)
    longpress.connect("pressed", fire)
    widget.add_controller(longpress)


class Favorites(Gtk.Box):
    def __init__(self, settings, on_launch):
        super().__init__(orientation=Gtk.Orientation.VERTICAL)
        self.add_css_class("favorites")
        self.settings = settings
        self._on_launch = on_launch
        self._apps = AstalApps.Apps()

        title = Gtk.Label(label="Favorites", xalign=0.0)
        title.add_css_class("section-title")
        self.append(title)

        self._row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
        self._row.add_css_class("favorites-row")
        scroller = Gtk.ScrolledWindow(
            vscrollbar_policy=Gtk.PolicyType.NEVER,
            hscrollbar_policy=Gtk.PolicyType.AUTOMATIC)
        scroller.set_child(self._row)
        self.append(scroller)

        settings.subscribe(self.refresh)
        self.refresh()

    def _by_entry(self) -> dict:
        return {a.get_entry(): a for a in self._apps.get_list() if a.get_entry()}

    def _resolve(self) -> list:
        by_entry = self._by_entry()
        entries = self.settings.favorites()
        if entries:
            return [by_entry[e] for e in entries if e in by_entry]
        # fallback: most-used apps
        apps = sorted(self._apps.get_list(), key=lambda a: -a.get_frequency())
        return [a for a in apps if a.get_frequency() > 0][:8]

    def refresh(self) -> None:
        child = self._row.get_first_child()
        while child:
            self._row.remove(child)
            child = self._row.get_first_child()
        apps = self._resolve()
        if not apps:
            self._row.append(Gtk.Label(label="Right-click an app below to pin it",
                                       xalign=0.0))
            return
        for app in apps:
            self._row.append(self._tile(app))

    def _tile(self, app) -> Gtk.Widget:
        btn = Gtk.Button()
        btn.add_css_class("fav-tile")
        content = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
        icon = Gtk.Image.new_from_icon_name(app.get_icon_name() or "application-x-executable")
        icon.set_pixel_size(28)
        content.append(icon)
        content.append(Gtk.Label(label=app.get_name(), ellipsize=3, max_width_chars=14))
        btn.set_child(content)
        btn.connect("clicked", lambda *_a: self._launch(app))
        # right-click / long-press unpins
        add_pin_gestures(btn, lambda: self.settings.toggle_favorite(app.get_entry()))
        return btn

    def _launch(self, app) -> None:
        try:
            app.launch()
        except Exception:
            pass
        self._on_launch()
