#!/usr/bin/python3

import gettext
import os
import subprocess
import sys

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

import apt
import apt.debfile

# i18n
gettext.install("guideos-common", "/usr/share/guideos/locale")

class MintRemoveWindow:

    def __init__(self, desktopFile):

        #find deb package
        self.desktopFile = desktopFile
        process = subprocess.run(["dpkg", "-S", self.desktopFile], stdout=subprocess.PIPE)
        output = process.stdout.decode("utf-8")
        package = output[:output.find(":")].split(",")[0]

        if process.returncode != 0: #deb package not found, try remove flatpack
            if not self.try_remove_flatpak(desktopFile):
                warnDlg = Gtk.MessageDialog(parent=None,
                                            flags=0,
                                            message_type=Gtk.MessageType.WARNING,
                                            buttons=Gtk.ButtonsType.YES_NO,
                                            text=_("This menu item is not associated to any package. Do you want to remove it from the menu anyway?"))
                warnDlg.get_widget_for_response(Gtk.ResponseType.YES).grab_focus()
                warnDlg.vbox.set_spacing(12)
                warnDlg.set_border_width(12)
                response = warnDlg.run()
                if response == Gtk.ResponseType.YES:
                    try:
                        os.remove(self.desktopFile)
                        # Show success message for desktop file removal
                        success_dialog = Gtk.MessageDialog(
                            parent=None,
                            flags=0,
                            type=Gtk.MessageType.INFO,
                            buttons=Gtk.ButtonsType.OK,
                            text=_("Menu item successfully removed!")
                        )
                        success_dialog.run()
                        success_dialog.destroy()
                    except OSError as error:
                        print("Could not remove desktop file in user mode.")
                        subprocess.call(["pkexec", "/usr/lib/guideos/common/guideos-remove-application.py", self.desktopFile])
                warnDlg.destroy()
            sys.exit(0)

        #get package + dependents (reverse dependencies)
        rdependenciesLines = subprocess.getoutput("apt-get -s -q remove " + package + " | grep Remv")
        rdependenciesLines = rdependenciesLines.split("\n")
        rdependencies = []
        for line in rdependenciesLines:
                rdependencies.append(line.split()[1])

        dontRemoves = ["cinnamon", "mint-meta-cinnamon", "mint-meta-core", "mint-meta-mate", "mint-meta-xfce"]
        if any(packageName in dontRemoves for packageName in rdependencies):
            self.no_remove_dialog(package, rdependencies)
        else:
            self.remove_dialog(package, rdependencies)

    def try_remove_flatpak(self, desktopFile):
        if not "flatpak" in desktopFile:
            return False

        if not os.path.exists('/usr/bin/guideos-remove-flatpak'):
            return False

        flatpak_remover = subprocess.Popen(['/usr/bin/guideos-remove-flatpak', desktopFile])
        retcode = flatpak_remover.wait()

        return retcode == 0

    def remove_dialog(self, package, rdependencies):
        #create dialogue
        warnDlg = Gtk.MessageDialog(parent=None,
                                    flags=0,
                                    message_type=Gtk.MessageType.WARNING,
                                    buttons=Gtk.ButtonsType.OK_CANCEL,
                                    text=_("The following packages will be removed:"))
        warnDlg.set_keep_above(True)

        warnDlg.get_widget_for_response(Gtk.ResponseType.OK).grab_focus()
        warnDlg.vbox.set_spacing(12)

        treeview = Gtk.TreeView()
        column1 = Gtk.TreeViewColumn(_("Packages to be removed"))
        renderer = Gtk.CellRendererText()
        column1.pack_start(renderer, False)
        column1.add_attribute(renderer, "text", 0)
        treeview.append_column(column1)

        packages_to_remove = rdependencies + self.get_autoremovable_dependencies(package)
        model = Gtk.ListStore(str)
        for item in packages_to_remove:
            model.append([item])

        treeview.set_model(model)
        treeview.show()

        scrolledwindow = Gtk.ScrolledWindow()
        scrolledwindow.set_shadow_type(Gtk.ShadowType.ETCHED_OUT)
        scrolledwindow.set_size_request(150, 150)
        scrolledwindow.add(treeview)
        scrolledwindow.show()

        warnDlg.get_content_area().add(scrolledwindow)
        warnDlg.set_border_width(12)

        response = warnDlg.run()
        if response == Gtk.ResponseType.OK:
            self.remove_packages_with_apt(packages_to_remove)
        elif response == Gtk.ResponseType.CANCEL:
            sys.exit(0)

        warnDlg.destroy()

    def remove_packages_with_apt(self, packages_to_remove):
        """Remove packages using pkexec and the polkit-authorized script"""
        try:
            # Create progress dialog
            progress_dialog = Gtk.MessageDialog(
                parent=None,
                flags=Gtk.DialogFlags.MODAL,
                type=Gtk.MessageType.INFO,
                buttons=Gtk.ButtonsType.NONE,
                text="Removing packages..."
            )
            progress_dialog.show_all()
            
            # Process events to show the dialog
            while Gtk.events_pending():
                Gtk.main_iteration()
            
            # Use pkexec to call the polkit-authorized removal script
            command = ["pkexec", "/usr/lib/guideos/common/guideos-remove-application.py"] + packages_to_remove
            process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdout, stderr = process.communicate()
            
            progress_dialog.destroy()
            
            if process.returncode == 0:
                # Show success dialog
                success_dialog = Gtk.MessageDialog(
                    parent=None,
                    flags=0,
                    type=Gtk.MessageType.INFO,
                    buttons=Gtk.ButtonsType.OK,
                    text=_("Packages successfully removed!")
                )
                success_msg = _("The following packages have been successfully removed:") + "\n\n"
                success_msg += "\n".join(packages_to_remove)
                success_dialog.format_secondary_markup(success_msg)
                success_dialog.run()
                success_dialog.destroy()
                self.on_finished()
            else:
                error_msg = stderr.decode('utf-8') if stderr else "Unknown error occurred"
                error_dialog = Gtk.MessageDialog(
                    parent=None,
                    flags=0,
                    type=Gtk.MessageType.ERROR,
                    buttons=Gtk.ButtonsType.OK,
                    text=_("Error removing packages: %s") % error_msg
                )
                error_dialog.run()
                error_dialog.destroy()
            
        except Exception as e:
            progress_dialog.destroy()
            error_dialog = Gtk.MessageDialog(
                parent=None,
                flags=0,
                type=Gtk.MessageType.ERROR,
                buttons=Gtk.ButtonsType.OK,
                text=f"Error removing packages: {str(e)}"
            )
            error_dialog.run()
            error_dialog.destroy()

    def get_autoremovable_dependencies(self, package):
        #Find autoremovable packages before removal of package
        output = subprocess.getoutput("apt-get -s -q autoremove | grep Remv")
        unreq_before = []
        if len(output) > 1:
            output = output.split("\n")
            for line in output:
                unreq_before.append(line.split()[1])

        #Find autoremovable packages after removal of package
        output = subprocess.getoutput("LC_ALL=C apt-get -s remove " + package)
        unreq_after = []
        begin = output.find("installed and are no longer required:")
        if begin > 0:
            output = output[begin + 37:output.find("Use '")]
            unreq_after = output.split()

        #find autoremovable packages due to removal of package
        additional_unreq = [item for item in unreq_after if item not in unreq_before]

        return additional_unreq

    def no_remove_dialog(self, package, rdependencies):
        warnDlg = Gtk.MessageDialog(parent=None,
                                    flags=0,
                                    message_type=Gtk.MessageType.ERROR,
                                    buttons=Gtk.ButtonsType.CLOSE,
                                    text=_("Cannot remove package %s as it is required by a system package.") % package)
        warnDlg.set_keep_above(True)
        warnDlg.get_widget_for_response(Gtk.ResponseType.CLOSE).grab_focus()
        warnDlg.vbox.set_spacing(12)

        treeview = Gtk.TreeView()
        column1 = Gtk.TreeViewColumn(_("Package %s is a dependency of the following packages:") % package)
        renderer = Gtk.CellRendererText()
        column1.pack_start(renderer, False)
        column1.add_attribute(renderer, "text", 0)
        treeview.append_column(column1)

        model = Gtk.ListStore(str)
        for rdependency in rdependencies:
            rdependency = rdependency.replace("Remv ", "")
            if package != rdependency.split()[0]:
                model.append([rdependency])

        treeview.set_model(model)
        treeview.show()

        scrolledwindow = Gtk.ScrolledWindow()
        scrolledwindow.set_shadow_type(Gtk.ShadowType.ETCHED_OUT)
        scrolledwindow.set_size_request(150, 150)
        scrolledwindow.add(treeview)
        scrolledwindow.show()

        warnDlg.get_content_area().add(scrolledwindow)
        warnDlg.set_border_width(12)

        response = warnDlg.run()
        sys.exit(0)

    def on_finished(self, transaction=None, exit_state=None):
        sys.exit(0)

if __name__ == "__main__":

    # Exit if the given path does not exist
    if len(sys.argv) < 2 or not os.path.exists(sys.argv[1]):
        print("No argument or file not found")
        sys.exit(1)

    path = sys.argv[1]
    dpath = f"{path}.desktop"
    if not os.path.exists(path):
        if os.path.exists(dpath):
            path = dpath
        else:
            print("Path not found", path)
            sys.exit(1)

    mainwin = MintRemoveWindow(path)
    Gtk.main()
