"""
Screen brightness control applet for the Panorama panel.
Copyright 2025, roundabout-host.com <vlad@roundabout-host.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public Licence as published by
the Free Software Foundation, either version 3 of the Licence, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public Licence for more details.

You should have received a copy of the GNU General Public Licence
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import os

import panorama_panel
import pydbus
import locale
from pathlib import Path
from pyudev import Context, Monitor, MonitorObserver

import gi
gi.require_version("Gtk", "4.0")

from gi.repository import Gtk, GLib, Gio


module_directory = Path(__file__).resolve().parent
locale.bindtextdomain("panorama-panel-file-listing", module_directory / "locale")
_ = lambda x: locale.dgettext("panorama-panel-file-listing", x)


def open_file_and_read_int(path: Path):
    with open(path) as f:
        return int(f.read().strip())


class ScreenBrightness(panorama_panel.Applet):
    name = _("Brightness")
    description = _("Control display brightness")

    def __init__(self, orientation=Gtk.Orientation.HORIZONTAL, config=None, **kwargs):
        super().__init__(orientation=orientation, config=config, **kwargs)
        if config is None:
            config = {}
        self.icon = Gtk.Image.new_from_icon_name("display-brightness-symbolic")
        self.icon.set_pixel_size(config.get("icon_size", 24))
        self.button = Gtk.MenuButton(child=self.icon, has_frame=False)
        self.append(self.button)
        self.popover = Gtk.Popover()
        self.box = Gtk.Box()
        self.popover.set_child(self.box)
        self.button.set_popover(self.popover)
        self.bus = pydbus.SystemBus()
        self.login1 = self.bus.get("org.freedesktop.login1", "/org/freedesktop/login1")
        self.manager = self.bus.get("org.freedesktop.login1", "/org/freedesktop/login1")
        self.session = self.bus.get("org.freedesktop.login1", self.manager.GetSessionByPID(os.getpid()))
        self.backlights = [path for path in Path("/sys/class/backlight").iterdir()]
        if not self.backlights:
            self.button.hide()
        self.adjustments = {}
        self.sessions = self.manager.ListSessions()
        self.udev_context = Context()
        self.monitor = Monitor.from_netlink(self.udev_context)
        self.monitor.filter_by(subsystem="backlight")
        self.observer = MonitorObserver(self.monitor, callback=self.process_notify)
        self.observer.start()
        self.update_backlights()

    def process_notify(self, device):
        # Called when the brightness is updated in any way, even externally
        path = Path("/sys/class/backlight") / device.sys_name
        adjustment = self.adjustments.get(path)
        value = open_file_and_read_int(path / "brightness")
        if not adjustment:
            return

        def update():
            adjustment.handler_block(adjustment.handler_id)
            adjustment.set_value(value)
            adjustment.handler_unblock(adjustment.handler_id)
            return False

        GLib.idle_add(update)

    def update_backlights(self):
        for backlight in self.backlights:
            max_brightness = open_file_and_read_int(backlight / "max_brightness")
            current_brightness = open_file_and_read_int(backlight / "brightness")
            adjustment = Gtk.Adjustment(lower=0, upper=max_brightness, value=current_brightness)
            adjustment.backlight = backlight
            self.adjustments[backlight] = adjustment
            adjustment.handler_id = adjustment.connect("value-changed", self.value_changed)
            scale = Gtk.Scale(adjustment=adjustment, width_request=200)
            self.box.append(scale)

    def value_changed(self, adjustment, *args):
        name = adjustment.backlight.name
        self.session.SetBrightness("backlight", name, int(adjustment.get_value()))

    def get_config(self):
        return {"icon_size": self.icon.get_pixel_size()}
