# window.py
#
# Copyright 2024 Etersoft
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: AGPL-3.0-or-later

from gi.repository import Gtk, Adw

import gettext
gettext.textdomain('eepm-play-gui')
_ = gettext.gettext

from .appsmanager import ApplicationManager
from .command_runner import CommandRunner

class LogDialog(Adw.Dialog):
    def __init__(self, win, **kwargs):
        super().__init__(**kwargs)
        self.set_title("Лог выполнения")
        self.set_can_close(False)
        self.set_follows_content_size(True)

        self.win = win

        dialog_clamp = Adw.Clamp(
            margin_bottom=12,
            margin_end=12,
            margin_top=12,
            margin_start=12,
            maximum_size=500
        )
        
        textview = Gtk.TextView()
        textview.set_editable(False)
        textview.set_cursor_visible(False)
        textbuffer = textview.get_buffer()

        scrolled_window = Gtk.ScrolledWindow(
            width_request=304,
            height_request=259
        )
        scrolled_window.set_child(textview)
        scrolled_window.set_vexpand(True)
        
        dialog_clamp.set_child(scrolled_window)

        self.set_child(dialog_clamp)

    def run(self, command, on_done):
        self.present(self.win)
        # Создание и передача функции обратного вызова для обновления UI
        runner = CommandRunner(on_done=on_done)
        runner.run_command(command, self)


@Gtk.Template(resource_path='/ru/eepm/PlayGUI/window.ui')
class EepmPlayGuiWindow(Adw.ApplicationWindow, LogDialog):
    __gtype_name__ = 'EepmPlayGuiWindow'
    search_entry = Gtk.Template.Child()
    search_dropdown = Gtk.Template.Child()

    loading_spinner = Gtk.Template.Child()
    choice_listbox = Gtk.Template.Child()
    apply_button = Gtk.Template.Child()

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.set_title("EPM PLAY")
        self.checkboxes = None

        self.apply_button.connect("activated", self.on_apply_clicked)
        
        self.search_entry.connect("search-changed", self.on_search_changed)
        self.search_dropdown.connect("notify::selected", self.on_filter_changed)
        
        self.choice_listbox.set_filter_func(self.listbox_filter_func)

        self.dialog = LogDialog(win=self)

        self.update_ui()

    def show_loading_spinner(self):
        self.loading_spinner.set_visible(True)
        self.choice_listbox.set_visible(False)  # Скрыть группу настроек во время загрузки

    def hide_loading_spinner(self):
        self.loading_spinner.set_visible(False)
        self.choice_listbox.set_visible(True)

    def on_applications_loaded(self, applications, error=None):
        if error:
            print(f"Error: {error}")
        else:
            self.applications = applications

    def update_ui(self):
        self.show_loading_spinner()  # Show loading again for installed apps

        self.update_button_status()

        ApplicationManager.get_available_applications(self.on_applications_loaded)
        ApplicationManager.get_installed_applications(self.on_installed_apps_loaded)

        self.choice_listbox.invalidate_filter()

    def on_installed_apps_loaded(self, installed_apps, error=None):
        if error:
            print(f"Error: {error}")
        else:
            self.installed_apps = installed_apps
            self.clear_choice_listbox()

            self.checkboxes = {}
            for app in self.applications:
                self.add_application_row(app)
            self.hide_loading_spinner()

    def clear_choice_listbox(self):
        self.choice_listbox.remove_all()

    def add_application_row(self, app):
        row = Adw.ActionRow(
            title=app['name'],
            subtitle=app['dscr']
        )
        
        checkbox = Gtk.CheckButton()
        checkbox.add_css_class("selection-mode")
        
        checkbox.set_active(app['name'] in self.installed_apps)
        
        checkbox.connect("toggled", self.on_checkbox_toggled, app['name'])
        
        row.add_suffix(checkbox)
        self.choice_listbox.append(row)
        self.checkboxes[app['name']] = checkbox

    def on_checkbox_toggled(self, checkbox, app_name):
        active = checkbox.get_active()
        print(f"{app_name} {'установлен' if active else 'снят'}")

        self.update_button_status()
    def update_button_status(self):
        to_install, to_remove = self.get_install_remove_lists()
        self.apply_button.remove_css_class("suggested-action")
        self.apply_button.remove_css_class("destructive-action")
        if to_install and to_remove:
            self.apply_button.add_css_class("suggested-action")
            self.apply_button.set_title(_("Remove and install applications"))
        elif to_install:
            self.apply_button.add_css_class("suggested-action")
            self.apply_button.set_title(_("Install applications"))
        elif to_remove:
            self.apply_button.add_css_class("destructive-action")
            self.apply_button.set_title(_("Remove applications"))
        else:
            self.apply_button.add_css_class("suggested-action")
            self.apply_button.set_title(_("Update applications"))

    def on_search_changed(self, search_entry):
        self.choice_listbox.invalidate_filter()  # Обновление фильтра при изменении поиска

    def on_filter_changed(self, dropdown, _pspec):
        self.choice_listbox.invalidate_filter()  # Обновление фильтра при изменении фильтра

    def listbox_filter_func(self, row):
        """Функция фильтрации для GtkListBox, которая проверяет текст и состояние фильтра"""
        search_text = self.search_entry.get_text().lower()
        filter_option = self.search_dropdown.get_selected()

        # Получение заголовка и подзаголовка строки
        title = row.get_title().lower() if row.get_title() else ''
        subtitle = row.get_subtitle().lower() if row.get_subtitle() else ''

        # Проверка текста поиска (по имени или описанию)
        matches_search = search_text in title or search_text in subtitle

        # Проверка по фильтру: установлено/не установлено в системе
        app_name = row.get_title() if row.get_title() else ''
        is_installed = app_name in self.installed_apps

        if filter_option == 1:  # Installed
            return matches_search and is_installed
        elif filter_option == 2:  # Uninstalled
            return matches_search and not is_installed
        else:
            return matches_search  # All

    def on_apply_clicked(self, button):
        self.show_loading_spinner()  # Показать сообщение о загрузке перед выполнением команды
        to_install, to_remove = self.get_install_remove_lists()
        commands = self.build_commands(to_install, to_remove)

        if commands:
            full_command = " && ".join(commands)
            pkexec_command = f'pkexec sh -c "{full_command}"'
            self.dialog.run(pkexec_command, on_done=self.update_ui)
        else:
            self.dialog.run("pkexec epm play --update all", on_done=self.update_ui)


    def get_install_remove_lists(self):
        if self.checkboxes:
            to_install = [app_name for app_name, checkbox in self.checkboxes.items() if checkbox.get_active() and app_name not in self.installed_apps]
            to_remove = [app_name for app_name, checkbox in self.checkboxes.items() if not checkbox.get_active() and app_name in self.installed_apps]
            return to_install, to_remove
        else:
            return False, False
    def build_commands(self, to_install, to_remove):
        commands = []
        if to_install:
            commands.append(f"epm play --auto {' '.join(to_install)}")
        if to_remove:
            commands.append(f"epm play --auto --remove {' '.join(to_remove)}")
        return commands