# Copyright 2021 Rafael Mardojai CM
# SPDX-License-Identifier: GPL-3.0-or-later

import os
from gettext import gettext as _
from random import randint

from gi.repository import Adw, Gio, GLib, Gtk

from blanket.define import RES_PATH
from blanket.settings import Settings


@Gtk.Template(resource_path=f"{RES_PATH}/preferences.ui")
class PreferencesDialog(Adw.PreferencesDialog):
    __gtype_name__ = "PreferencesDialog"

    dark_group: Adw.PreferencesGroup = Gtk.Template.Child()  # type: ignore
    dark: Adw.SwitchRow = Gtk.Template.Child()  # type: ignore
    autostart: Adw.SwitchRow = Gtk.Template.Child()  # type: ignore
    start_paused: Adw.SwitchRow = Gtk.Template.Child()  # type: ignore
    inhibition: Adw.SwitchRow = Gtk.Template.Child()  # type: ignore

    def __init__(self, window, **kwargs):
        super().__init__(**kwargs)

        self.window = window

        # Show dark theme preference if system does not support color schemes
        self.dark_group.props.visible = (
            not Adw.StyleManager.get_default().props.system_supports_color_schemes
        )
        # Dark theme
        Settings.get().bind(
            "dark-mode", self.dark, "active", Gio.SettingsBindFlags.DEFAULT
        )
        self.dark.connect("notify::active", self._toggle_dark)

        # Autostart
        self.autostart_failed = False
        self.autostart_saved = Settings.get().autostart
        self.autostart.props.active = self.autostart_saved
        self.autostart.connect("notify::active", self._toggle_autostart)

        # Start paused
        Settings.get().bind(
            "start-paused", self.start_paused, "active", Gio.SettingsBindFlags.DEFAULT
        )

        # Inhibition
        Settings.get().bind(
            "inhibit-suspension",
            self.inhibition,
            "active",
            Gio.SettingsBindFlags.DEFAULT,
        )

    def _toggle_dark(self, switch: Adw.SwitchRow, _pspec):
        style_manager = Adw.StyleManager.get_default()
        if switch.props.active:
            style_manager.props.color_scheme = Adw.ColorScheme.FORCE_DARK
        else:
            style_manager.props.color_scheme = Adw.ColorScheme.PREFER_LIGHT

    def _toggle_autostart(self, switch: Adw.SwitchRow, _pspec):
        self.__request_autostart(switch.props.active)

    def __request_autostart(self, active: bool):
        if self.autostart_failed:
            self.autostart_failed = False
            return

        bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
        proxy = Gio.DBusProxy.new_sync(
            bus,
            Gio.DBusProxyFlags.NONE,
            None,
            "org.freedesktop.portal.Desktop",
            "/org/freedesktop/portal/desktop",
            "org.freedesktop.portal.Background",
            None,
        )

        identifier = self.__get_window_identifier()
        token = 0 + randint(10000000, 90000000)
        options = {
            "handle_token": GLib.Variant("s", f"com/rafaelmardojai/Blanket/{token}"),
            "reason": GLib.Variant("s", _("Autostart Blanket in background.")),
            "autostart": GLib.Variant("b", active),
            "commandline": GLib.Variant("as", ["blanket", "--hidden"]),
            "dbus-activatable": GLib.Variant("b", False),
        }

        try:
            request = proxy.RequestBackground("(sa{sv})", identifier, options)  # type: ignore
            if request is None:
                raise Exception(
                    "The DBus proxy didn't return an object path."
                    + "\nThe portal can't subscribe to the signal."
                )

            bus.signal_subscribe(
                "org.freedesktop.portal.Desktop",
                "org.freedesktop.portal.Request",
                "Response",
                request,
                None,
                Gio.DBusSignalFlags.NO_MATCH_RULE,
                self.__receive_autostart,
                None,
            )

        except Exception as e:
            print(e)

            error_dialog = Adw.AlertDialog.new(
                _("Request error"), _("The autostart request failed.")
            )
            error_dialog.add_response("ok", _("Ok"))
            error_dialog.present(self.window)
            self.autostart_failed = True
            self.autostart.set_active(self.autostart_saved)

    def __receive_autostart(self, *args):
        self.window.present()

        active = self.autostart.get_active()
        state = args[5][0]
        autostart = args[5][1]["autostart"]

        if state == 0:
            pass
        elif state == 1:
            if active:
                error_dialog = Adw.AlertDialog.new(
                    _("Authorization failed"),
                    _(
                        "Make sure Blanket has permission to run in the background in Settings → Applications → Blanket and try again."
                    ),
                )
                error_dialog.add_response("ok", _("Ok"))
                error_dialog.present(self.window)
        elif state == 2:
            error_dialog = Adw.AlertDialog.new(
                _("Request error"), _("The autostart request failed.")
            )
            error_dialog.add_response("ok", _("Ok"))
            error_dialog.present(self.window)

        self.autostart.set_active(autostart)
        Settings.get().autostart = autostart
        return

    def __get_window_identifier(self):
        session = os.getenv("XDG_SESSION_TYPE")
        surface = self.window.get_surface()

        if session == "x11":
            return f"x11:{str(surface.get_xid())}"
        elif session == "wayland":
            return "wayland:"
        return ""
