# combo_row.py
#
# Copyright 2025 Mitchell Winkelman (Heliguy)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, 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 License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: GPL-3.0-or-later

from typing import TYPE_CHECKING, Any, cast

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

from refine.logger import logger
from refine.widgets.base import BaseInterface

if TYPE_CHECKING:
    from gi.repository import GLib


class ComboRow(Adw.ComboRow, BaseInterface):
    """
    Base combo row widget implementing the `schema-id` and `key` properties.

    It is assumed to derive from it, rather than using it directly.
    """

    __gtype_name__ = "ComboRow"

    is_valid_setting = cast("bool", GObject.Property(type=bool, default=False))
    settings = cast("Gio.Settings", GObject.Property(type=Gio.Settings))
    schema = cast("Gio.SettingsSchema", GObject.Property(type=Gio.SettingsSchema))
    schema_id = cast("str", GObject.Property(type=str))
    key = cast("str", GObject.Property(type=str))

    restart_required = GObject.Property(type=bool, default=False)
    is_default = GObject.Property(type=bool, default=True)

    original_list: list[str]
    transformed_list: list[str]
    revert_button: Gtk.Button
    revealer: Gtk.Revealer

    def _settings_changed(self, *_args: Any) -> None:
        row_string = self.original_list[self.get_selected()]
        settings_string = self.settings.get_string(self.key)

        if row_string != settings_string:
            self.emit("inconsistent")

    def _inconsistent_set(self, *_args: Any) -> None:
        self.handler_block_by_func(self.selected_callback)  # type: ignore [no-untyped-call]

        string = self.settings.get_string(self.key)

        self.set_selected(self.original_list.index(string))
        self.set_is_default(self.key)

        self.handler_unblock_by_func(self.selected_callback)  # type: ignore [no-untyped-call]

    def _reset_button_clicked(self, *_args: Any) -> None:
        logger.debug("Revert button pressed")

        string_object = cast(
            "Gtk.StringObject", self.settings.get_default_value(self.key)
        )
        if not string_object:
            return

        string = string_object.get_string()

        self.settings.reset(self.key)
        self.set_selected(self.original_list.index(string))
        self.set_is_default(self.key)

    def set_is_default(self, key: str) -> None:
        """Update the `ComboRow.is-default` property."""
        default_value = cast("GLib.Variant", self.settings.get_default_value(key))
        default_string = default_value.get_string()

        row_string = self.original_list[self.get_selected()]

        self.is_default = row_string == default_string

    def selected_callback(self, *_args: Any) -> None:
        """Callback method for selecting an item."""
        row_string = self.original_list[self.get_selected()]

        self.set_is_default(self.key)
        self.settings.set_string(self.key, row_string)
        self.value_set(row_string)

    def value_set(self, value: Any) -> None:
        """Log key-value pair."""
        logger.debug(f"Set key “{self.key}” to “{value}”")

        if not self.restart_required:
            return

        if not (window := self.get_root()):
            raise AssertionError

        window.emit("restart-items-changed", self)

    def do_setup(self) -> None:
        self.revert_button.connect("clicked", self._reset_button_clicked)
        self.bind_property(
            "is-default",
            self.revert_button,
            "sensitive",
            GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.INVERT_BOOLEAN,
        )
        BaseInterface.set_up_separator_revealer(self.revealer, self.revert_button)
        self.connect("inconsistent", self._inconsistent_set)
        self.settings.connect("changed", self._settings_changed)

    @GObject.Signal
    def inconsistent(self) -> None:
        """Log inconsistency signal."""
        logger.info(f"{self.__class__.__name__}::inconsistent signal emitted")
