#!/usr/bin/env python3
"""
Controller for the settings view.
"""

import subprocess
import json
import threading
import gettext

from logging_config import logger
from app_shared import (
    show_dialog,
    DialogIcon
)

import gi
gi.require_version('GLib', '2.0')
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, GLib  #pylint: disable=wrong-import-position


_ = gettext.translation('deb-software', fallback=True).gettext

class SettingsController:
    """
    Controller for the settings view.
    """
    def __init__(self, app, settings_model, settings_view, main_view):
        self.app = app
        self.model = settings_model
        self.view = settings_view
        self.main_view = main_view

        # Timeout ID for progress bar
        self._progress_timeout_id = None

        # Track results of all operations
        self._flatpak_ok = True
        self._interval_ok = True
        self._indicator_ok = True

    # -----------------------------
    # Save all settings
    # -----------------------------
    def save_all(
        self,
        repo_checkbuttons: list[Gtk.CheckButton],
        flatpak_check: Gtk.CheckButton,
        interval_combo: Gtk.ComboBoxText | None,
        checker_check: Gtk.CheckButton
    ) -> None:
        """
        Save all settings.

        Args:
            repo_checkbuttons (list[Gtk.CheckButton]): List of repository checkbuttons.
            flatpak_check (Gtk.CheckButton): Flatpak checkbutton.
            interval_combo (Gtk.ComboBoxText): Interval combobox.
            checker_check (Gtk.CheckButton): Update checker checkbutton.
        """
        repositories = [(btn.uri, btn.get_active()) for btn in repo_checkbuttons]

        # -----------------------------
        # Save Flatpak
        # -----------------------------
        if flatpak_check.get_active():
            self._flatpak_ok = self.app.enable_flatpak()
        else:
            self._flatpak_ok = self.app.disable_flatpak()

        # -----------------------------
        # Save interval
        # -----------------------------
        if interval_combo is not None:
            interval = interval_combo.interval_values[interval_combo.get_active()]
            self._interval_ok = self.model.set_check_interval(interval)

        # -----------------------------
        # Save update checker
        # -----------------------------
        if checker_check.get_active():
            self._indicator_ok = self.model.enable_update_indicator()
        else:
            self._indicator_ok = self.model.disable_update_indicator()

        # -----------------------------
        # Save repositories asynchronously
        # -----------------------------
        self._save_repositories_async(repositories)

    # -----------------------------
    # Async repository saving
    # -----------------------------
    def _save_repositories_async(self, repositories: list[tuple[str, bool]]) -> None:
        # Check for changes
        changes = False
        user_repos = dict(repositories)

        for src in self.model.sources.list:
            if src.uri in user_repos:
                if user_repos[src.uri] != (not src.disabled):
                    changes = True
                    break

        # -----------------------------
        # No changes > no async operation
        # -----------------------------
        if not changes:
            # Still call completion handler so the dialog is shown
            GLib.idle_add(self._on_save_complete, True)
            return

        # -----------------------------
        # Changes > run async pkexec
        # -----------------------------
        self._progress_timeout_id = GLib.timeout_add(100, self._pulse_progressbar)

        def worker():
            try:
                logger.debug("Saving repositories: %s", repositories)
                repo_json = json.dumps(repositories)
                subprocess.run(
                    ["pkexec", "/usr/lib/deb-software/scripts/save_repositories_helper"],
                    input=repo_json.encode(),
                    check=True
                )
                # Refresh updates and restart checker but stay in settings
                self.app.refresh_data(show_updates=False)
                self.model.restart_update_indicator()

                # Call completion handler
                GLib.idle_add(self._on_save_complete, True)
            except Exception as e:    # pylint: disable=broad-except
                logger.exception("Failed to save repositories: %s", e)
                GLib.idle_add(self._on_save_complete, False)

        threading.Thread(target=worker, daemon=True).start()

    def _pulse_progressbar(self) -> bool:
        self.main_view.progressbar.pulse()
        return True

    # -----------------------------
    # Final result handling
    # -----------------------------
    def _on_save_complete(self, repo_ok: bool) -> None:
        # Refresh sources
        self.model.reload_sources()

        # Stop pulsing the progress bar
        if self._progress_timeout_id:
            GLib.source_remove(self._progress_timeout_id)
            self._progress_timeout_id = None

        self.main_view.progressbar.set_fraction(0)
        self.main_view.save_settings.set_sensitive(True)

        # Combine all results
        all_ok = repo_ok and self._flatpak_ok and self._interval_ok and self._indicator_ok

        # Build message
        if all_ok:
            title = self.main_view.window.get_title()
            icon = DialogIcon.INFO
            message = _("All settings were saved successfully.")
        else:
            title = _("Settings not fully saved")
            icon = DialogIcon.ERROR

            parts = []
            if not repo_ok:
                parts.append(_("* Failed to save repositories"))
            if not self._flatpak_ok:
                parts.append(_("* Failed to save Flatpak"))
            if not self._interval_ok:
                parts.append(_("* Failed to save update interval"))
            if not self._indicator_ok:
                parts.append(_("* Failed to save the update checker state"))

            message = "\n".join(parts)

        # Show dialog
        show_dialog(
            title,
            message,
            self.main_view.window,
            icon
        )
