#!/usr/bin/env python3
"""
Themes tab for SolydXK System

Author: Arjen Balfoort
Date: 2026-02-22
"""

import os
import queue
import gettext

from themes import Plymouth, Grub, Themes
from utils import (
    show_dialog,
    DialogIcon,
    SudoCommandThread,
    LogLevel,
    DebSoftwareApp,
    LogLevel_To_DialogIcon
)

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, GLib

# i18n: http://docs.python.org/3/library/gettext.html
_ = gettext.translation('solydxk-system', fallback=True).gettext


class TabThemes:
    """
    Themes tab for SolydXK System
    """
    def __init__(self, app: DebSoftwareApp) -> None:
        self.app: DebSoftwareApp = app
        self.grub: Grub = Grub(self.app.logging)
        self.plymouth: Plymouth = Plymouth(self.app.logging)
        self.plymouth_checkboxes: list[Gtk.CheckButton] = []
        self.grub_checkboxes: list[Gtk.CheckButton] = []

    def setup_themes_tab(self) -> None:
        """
        Set up the theming tab.
        """
        # Reset the progress bar
        self.app.progressbar.set_fraction(0)

        # Check if the listboxes are already set up
        if self.app.listbox_plymouth.get_row_at_index(0) is not None:
            return

        if self.plymouth.installed_themes:
            self._fill_listbox(Themes.PLYMOUTH)
        else:
            self.app.save_plymouth_button.set_sensitive(False)

        # Get Grub themes
        if self.grub.installed_themes:
            self._fill_listbox(Themes.GRUB)
        else:
            self.app.save_grub_button.set_sensitive(False)

        # Fill the resolution dropdown
        string_list = Gtk.StringList.new([])
        for resolution, ratio in self.grub.get_all_resolutions():
            string_list.append(f"{resolution} {ratio}")
        self.app.dd_resolution.set_model(string_list)

        # Select the current resolution
        current_resolution, current_ratio = self.grub.get_current_resolution()
        if current_resolution is None and current_ratio is None:
            self.app.dd_resolution.set_selected(0)
        else:
            current_str = f"{current_resolution} {current_ratio}"
            for i in range(string_list.get_n_items()):
                if string_list.get_string(i) == current_str:
                    self.app.dd_resolution.set_selected(i)
                    break

        self.app.save_grub_button.connect('clicked', self.on_save_grub_clicked)
        self.app.save_plymouth_button.connect('clicked', self.on_save_plymouth_clicked)

    @staticmethod
    def on_checkbox_toggled(checkbox: Gtk.CheckButton,
                            checked_list: list[Gtk.CheckButton]):
        """
        Handle the checkbox toggle event.

        Args:
            checkbox (Gtk.CheckButton): The checkbox that was toggled.
            checked_list (list): The list of checked checkboxes.
        """
        if checkbox.get_active():
            if len(checked_list) >= 1:
                # Uncheck the oldest checked checkbox
                oldest = checked_list.pop(0)
                oldest.set_active(False)
            checked_list.append(checkbox)
        else:
            if checkbox in checked_list:
                checked_list.remove(checkbox)

    def on_save_grub_clicked(self, _button: Gtk.Button) -> None:
        """
        Handle the Grub save button click event.
        """
        message = ''
        # Get the selected resolution
        selected = self.app.dd_resolution.get_selected_item().get_string()
        resolution, _unused = selected.rsplit(' ', 1)

        if not resolution:
            show_dialog(_("Themes"),
                        _("Please select a resolution."),
                        self.app.window,
                        DialogIcon.WARNING)
            return

        # Get the selected Grub theme
        theme_name = None
        row: Gtk.ListBoxRow | None = self.app.listbox_grub.get_first_child()
        while row is not None:
            checkbox: Gtk.CheckButton = row.get_child()
            if checkbox.get_active():
                theme_name = checkbox.theme_name
                break
            row = row.get_next_sibling()

        if theme_name is None:
            show_dialog(_("Themes"),
                        _("Please select a Grub theme."),
                        self.app.window,
                        DialogIcon.WARNING)
            return

        self.app.logging.info("Selected Grub theme: %s", theme_name)

        # Save the Grub theme
        theme_name = '' if theme_name is None else theme_name
        resolution = '' if resolution is None or theme_name is None else resolution
        result_queue = queue.Queue()

        # pkexec will prompt for root password via polkit
        command = ["pkexec",
                   "--disable-internal-agent",
                   "python3",
                   os.path.join(self.app.script_dir, "themes_sudo.py"),
                   'grub',
                   theme_name,
                   resolution]

        thread = SudoCommandThread(command,
                                   _("Grub theme"),
                                   result_queue,
                                   self.app.logging)
        thread.start()

        # Use a timeout to update the progress bar
        def update_progress():
            nonlocal message
            if not result_queue.empty():
                dict_info = result_queue.get()
                level = dict_info['level']
                message = dict_info.get('message')

                if level == LogLevel.ERROR:
                    # An error occurred
                    show_dialog(_("Themes"),
                                message,
                                self.app.window,
                                DialogIcon.ERROR)
                    self.app.progressbar.set_fraction(0)
                    self.app.progressbar_label.set_text("")
                    return False

                self.app.progressbar.set_fraction(dict_info['progress'] / 100)
                self.app.progressbar_label.set_text(message)

            if not thread.is_alive() and result_queue.empty():
                # Show dialog
                if level == LogLevel.SUCCESS:
                    message = _("Grub theme saved successfully.")
                show_dialog(_("Themes"),
                            message,
                            self.app.window,
                            LogLevel_To_DialogIcon.get(level, DialogIcon.INFO))
                self.app.progressbar_label.set_text("")

                # All done
                return False

            # Keep going
            return True

        # Add the timeout callback (runs every 100ms)
        GLib.timeout_add(100, update_progress)

    def on_save_plymouth_clicked(self, _button: Gtk.Button) -> None:
        """
        Handle the Plymouth save button click event.
        """
        message = ''
        # Get the selected Plymouth theme
        theme_name = None
        row: Gtk.ListBoxRow | None = self.app.listbox_plymouth.get_first_child()
        while row is not None:
            checkbox: Gtk.CheckButton = row.get_child()
            if checkbox.get_active():
                theme_name = checkbox.theme_name
                break
            row = row.get_next_sibling()

        self.app.logging.info("Selected Plymouth theme: %s", theme_name)

        # Save the Plymouth theme
        theme_name = '' if theme_name is None else theme_name
        result_queue = queue.Queue()

        # pkexec will prompt for root password via polkit
        command = ["pkexec",
                   "--disable-internal-agent",
                   "python3",
                   os.path.join(self.app.script_dir, "themes_sudo.py"),
                   'plymouth',
                   theme_name]

        thread = SudoCommandThread(command,
                                   _("Plymouth theme"),
                                   result_queue,
                                   self.app.logging)
        thread.start()

        # Use a timeout to update the progress bar
        def update_progress():
            nonlocal message
            if not result_queue.empty():
                dict_info = result_queue.get()
                level = dict_info['level']
                message = dict_info.get('message')

                if level == LogLevel.ERROR:
                    # An error occurred
                    show_dialog(_("Themes"),
                                message,
                                self.app.window,
                                DialogIcon.ERROR)
                    self.app.progressbar.set_fraction(0)
                    self.app.progressbar_label.set_text("")
                    return False

                self.app.progressbar.set_fraction(dict_info['progress'] / 100)
                self.app.progressbar_label.set_text(message)

            if not thread.is_alive() and result_queue.empty():
                # Show dialog
                if level == LogLevel.SUCCESS:
                    message = _("Plymouth theme saved successfully.")
                show_dialog(_("Themes"),
                            message,
                            self.app.window,
                            LogLevel_To_DialogIcon.get(level, DialogIcon.INFO))
                self.app.progressbar_label.set_text("")

                # All done
                return False

            # Keep going
            return True

        # Add the timeout callback (runs every 100ms)
        GLib.timeout_add(100, update_progress)

    def _fill_listbox(self, theme: Themes) -> None:
        """
        Fill the listbox with the given data.

        Args:
            listbox (Gtk.ListBox): The listbox to fill.
            data (list[str]): The data to fill the listbox with.
        """
        if theme == Themes.PLYMOUTH:
            listbox = self.app.listbox_plymouth
            themes = self.plymouth.installed_themes
            current_theme = self.plymouth.get_current_theme()
        else:
            listbox = self.app.listbox_grub
            themes = self.grub.installed_themes
            current_theme = self.grub.get_current_theme()

        for theme_name in themes:
            enabled = theme_name == current_theme
            # Create a row
            row = Gtk.ListBoxRow()

            # Add checkbox
            checkbox = Gtk.CheckButton()
            checkbox.set_active(enabled)
            checkbox.theme_name = theme_name
            checkbox.set_label(theme_name)
            save_array = self.plymouth_checkboxes if theme == Themes.PLYMOUTH \
                         else self.grub_checkboxes
            checkbox.connect("toggled", self.on_checkbox_toggled, save_array)
            row.set_child(checkbox)

            listbox.append(row)

            if enabled:
                # Save the checked checkbox to keep history
                dbg = ""
                if theme == Themes.PLYMOUTH:
                    self.plymouth_checkboxes.append(checkbox)
                    for chk in self.plymouth_checkboxes:
                        dbg += f"{chk.get_label().strip()},"
                    self.app.logging.debug("self.plymouth_checkboxes: %s", dbg)
                else:
                    self.grub_checkboxes.append(checkbox)
                    for chk in self.grub_checkboxes:
                        dbg += f"{chk.get_label().strip()},"
                    self.app.logging.debug("self.grub_checkboxes: %s", dbg)
