from gettext import gettext as _
import gi

gi.require_version("GtkSource", "5")
from gi.repository import Adw, Gio, GObject, Gtk, GtkSource

import iotas.config_manager
from iotas.ui_utils import add_mouse_button_accel
from iotas.ui_utils import ComboRowHelper


@Gtk.Template(resource_path="/org/gnome/World/Iotas/ui/preferences_window.ui")
class PreferencesWindow(Adw.PreferencesWindow):
    __gtype_name__ = "PreferencesWindow"

    CLICKS_FOR_EXTENDED = 6

    _index_group = Gtk.Template.Child()
    _editor_theme_row = Gtk.Template.Child()
    _index_category_style_row = Gtk.Template.Child()
    _disconnect_sync = Gtk.Template.Child()
    _debug_page = Gtk.Template.Child()
    _enable_render_view = Gtk.Template.Child()
    _markdown_default_to_render = Gtk.Template.Child()
    _enable_markdown_maths = Gtk.Template.Child()
    _keep_webkit_process = Gtk.Template.Child()
    _markdown_use_monospace_font = Gtk.Template.Child()
    _markdown_monospace_font_ratio = Gtk.Template.Child()
    _hide_editor_headerbar_when_fullscreen = Gtk.Template.Child()

    def __init__(self):
        super().__init__()
        self.__app = Gio.Application.get_default()
        self.set_transient_for(self.__app.get_active_window())

        self.__dependent_on_markdown_render = [
            self._markdown_default_to_render,
            self._enable_markdown_maths,
            self._markdown_use_monospace_font,
            self._markdown_monospace_font_ratio,
            self._keep_webkit_process,
        ]

        self.__build_actions()

        scheme_manager = GtkSource.StyleSchemeManager.get_default()
        options = []
        scheme_ids = scheme_manager.get_scheme_ids()

        # Preference and order internal schemes
        def add_preferenced_scheme(scheme_id):
            if scheme_id not in scheme_ids:
                return
            scheme = scheme_manager.get_scheme(scheme_id)
            options.append((scheme.get_name(), scheme_id))

        preferenced_schemes = ("iotas-mono", "iotas-alpha-muted", "iotas-alpha-bold")
        for scheme_id in preferenced_schemes:
            add_preferenced_scheme(scheme_id)

        # Add other schemes (eg. in user data)
        for scheme_id in scheme_ids:
            if scheme_id in preferenced_schemes:
                continue
            # Only Iotas-specific schemes, prefixed with "iotas-", are supported
            if scheme_id.startswith("iotas-") and not scheme_id.endswith("-dark"):
                scheme = scheme_manager.get_scheme(scheme_id)
                options.append((scheme.get_name(), scheme_id))

        helper = ComboRowHelper(
            self._editor_theme_row,
            options,
            iotas.config_manager.get_editor_theme(),
        )
        helper.connect("changed", self.__on_editor_theme_changed)

        options = (
            # Translators: Description, a visual style (for category labels in index)
            (_("Monochrome"), "monochrome"),
            # Translators: Description, a visual style (for category labels in index)
            (_("Muted"), "muted"),
            # Translators: Description, a visual style (for category labels in index)
            (_("Blue"), "blue"),
            # Translators: Description, a visual style (for category labels in index)
            (_("Orange"), "orange"),
            # Translators: Description, a visual style (for category labels in index)
            (_("Red"), "red"),
            # Translators: Description, a visual style (for category labels in index)
            (_("None"), "none"),
        )
        helper = ComboRowHelper(
            self._index_category_style_row,
            options,
            iotas.config_manager.get_index_category_style(),
        )
        helper.connect("changed", self.__on_index_category_style_changed)

        self._markdown_monospace_font_ratio.connect(
            "notify::value", self.__on_markdown_spinrow_changed
        )
        iotas.config_manager.settings.connect(
            f"changed::{iotas.config_manager.MARKDOWN_RENDER_MONOSPACE_FONT_RATIO}",
            self.__on_markdown_font_size_ratio_config_changed,
        )
        self.__update_markdown_font_ratio_from_config()

        self._disconnect_sync.set_visible(iotas.config_manager.nextcloud_sync_configured())
        if not (self.__app.debug_session or self.__app.development_mode):
            self.remove(self._debug_page)

        iotas.config_manager.settings.connect(
            f"changed::{iotas.config_manager.MARKDOWN_RENDER}", self.__on_markdown_render_changed
        )
        self.__update_disabled_markdown_render_items()

        self.__init_excessive_preferences_handling()
        self.__toast = None

    def __build_actions(self) -> None:
        action_group = Gio.SimpleActionGroup.new()

        key = iotas.config_manager.USE_MONOSPACE_FONT
        monospace_font_action = iotas.config_manager.settings.create_action(key)
        action_group.add_action(monospace_font_action)

        key = iotas.config_manager.PERSIST_SIDEBAR
        persist_sidebar_action = iotas.config_manager.settings.create_action(key)
        action_group.add_action(persist_sidebar_action)

        key = iotas.config_manager.SPELLING_ENABLED
        spelling_action = iotas.config_manager.settings.create_action(key)
        action_group.add_action(spelling_action)

        key = iotas.config_manager.HIDE_EDITOR_HEADERBAR
        hide_headerbar = iotas.config_manager.settings.create_action(key)
        action_group.add_action(hide_headerbar)

        key = iotas.config_manager.HIDE_HEADERBAR_WHEN_FULLSCREEN
        hide_headerbar_when_fullscreen_action = iotas.config_manager.settings.create_action(key)
        action_group.add_action(hide_headerbar_when_fullscreen_action)

        key = iotas.config_manager.MARKDOWN_SYNTAX_HIGHLIGHTING
        syntax_action = iotas.config_manager.settings.create_action(key)
        action_group.add_action(syntax_action)

        key = iotas.config_manager.MARKDOWN_RENDER
        render_action = iotas.config_manager.settings.create_action(key)
        action_group.add_action(render_action)

        key = iotas.config_manager.MARKDOWN_DEFAULT_TO_RENDER
        default_render_action = iotas.config_manager.settings.create_action(key)
        action_group.add_action(default_render_action)

        key = iotas.config_manager.MARKDOWN_TEX_SUPPORT
        tex_action = iotas.config_manager.settings.create_action(key)
        action_group.add_action(tex_action)

        key = iotas.config_manager.MARKDOWN_USE_MONOSPACE_FONT
        markdown_monospace_action = iotas.config_manager.settings.create_action(key)
        action_group.add_action(markdown_monospace_action)

        key = iotas.config_manager.MARKDOWN_KEEP_WEBKIT_PROCESS
        keep_webkit_action = iotas.config_manager.settings.create_action(key)
        action_group.add_action(keep_webkit_action)

        self.insert_action_group("settings", action_group)

    def __init_excessive_preferences_handling(self) -> None:
        """An experiment in providing configurabiliy for more technical users while retaining
        simplicy for those less savvy.

        This is an experiment, and may get removed.
        """

        self.__extended_only = [
            self._index_category_style_row,
            self._enable_render_view,
            self._markdown_default_to_render,
            self._enable_markdown_maths,
            self._keep_webkit_process,
            self._hide_editor_headerbar_when_fullscreen,
            self._markdown_use_monospace_font,
            self._markdown_monospace_font_ratio,
        ]
        self.__update_showing_extended()
        iotas.config_manager.settings.connect(
            f"changed::{iotas.config_manager.SHOW_EXTENDED_PREFERENCES}",
            self.__on_show_extended_preferences_changed,
        )

        iotas.config_manager.settings.connect(
            f"changed::{iotas.config_manager.HIDE_EDITOR_HEADERBAR}",
            self.__on_hide_headerbar_changed,
        )

        # Ouch, hacky. Fetch a bunch of widgets to add click listeners to.
        box = self._index_group.get_parent()
        clamp = box.get_parent()
        for widget in box, clamp:
            add_mouse_button_accel(
                widget, self.__on_preferences_background_click, Gtk.PropagationPhase.TARGET
            )

    def __on_preferences_background_click(
        self, gesture: Gtk.GestureClick, n_press: int, _x: float, _y: float
    ) -> None:
        extended = iotas.config_manager.get_show_extended_preferences()
        if gesture.get_current_button() != 1:
            return
        if n_press > 1 and n_press < self.CLICKS_FOR_EXTENDED:
            clicks = self.CLICKS_FOR_EXTENDED - n_press
            if extended:
                # Translators: Description, notification, {0} is a number
                text = _("Reducing in {0} presses").format(clicks)
            else:
                # Translators: Description, notification, {0} is a number
                text = _("Extending in {0} presses").format(clicks)
            self.__make_toast(text)
        elif n_press == self.CLICKS_FOR_EXTENDED:
            if extended:
                # Translators: Description, notification
                self.__make_toast(_("Extended hidden"))
            else:
                # Translators: Description, notification
                self.__make_toast(_("Extended shown"))
            iotas.config_manager.set_show_extended_preferences(not extended)

    def __make_toast(self, text: str) -> None:
        if self.__toast is not None:
            self.__toast.dismiss()
        toast = Adw.Toast.new(text)
        toast.set_priority(Adw.ToastPriority.HIGH)
        toast.set_timeout(2)
        toast.connect("dismissed", self.__toast_dismissed)
        self.__toast = toast
        self.add_toast(toast)

    def __toast_dismissed(self, _toast: Adw.Toast) -> None:
        self.__toast = None

    @Gtk.Template.Callback()
    def _reset_database(self, _button: Gtk.Button) -> None:
        self.__app.reset_database()

    @Gtk.Template.Callback()
    def _disconnect_nextcloud(self, _button: Gtk.Button) -> None:
        self.__app.disconnect_nextcloud()

    @Gtk.Template.Callback()
    def _reset_prune_threshold(self, _button: Gtk.Button) -> None:
        self.__app.reset_sync_marker()

    def __on_editor_theme_changed(self, _obj: GObject.Object, value: str) -> None:
        iotas.config_manager.set_editor_theme(value)

    def __on_index_category_style_changed(self, _obj: GObject.Object, value: str) -> None:
        iotas.config_manager.set_index_category_style(value)

    def __on_show_extended_preferences_changed(self, _obj: Gio.Settings, _key: str) -> None:
        self.__update_showing_extended()

    def __on_markdown_render_changed(self, _obj: Gio.Settings, _key: str) -> None:
        self.__update_disabled_markdown_render_items()

    def __on_markdown_font_size_ratio_config_changed(self, _obj: Gio.Settings, _key: str) -> None:
        self.__update_markdown_font_ratio_from_config()

    def __on_markdown_spinrow_changed(self, _obj: GObject.Object, _value: GObject.ParamSpec):
        iotas.config_manager.set_markdown_render_monospace_font_ratio(
            self._markdown_monospace_font_ratio.get_value()
        )

    def __on_hide_headerbar_changed(self, _obj: Gio.Settings, _key: str) -> None:
        self.__update_showing_extended()

    def __update_markdown_font_ratio_from_config(self) -> None:
        self._markdown_monospace_font_ratio.set_value(
            iotas.config_manager.get_markdown_render_monospace_font_ratio()
        )

    def __update_disabled_markdown_render_items(self) -> None:
        enabled = iotas.config_manager.get_markdown_render_enabled()
        for widget in self.__dependent_on_markdown_render:
            widget.set_sensitive(enabled)

    def __update_showing_extended(self) -> None:
        showing_extended = iotas.config_manager.get_show_extended_preferences()
        for obj in self.__extended_only:
            obj.set_visible(showing_extended)

        self._hide_editor_headerbar_when_fullscreen.set_sensitive(
            not iotas.config_manager.get_hide_editor_headerbar()
        )
