#!/usr/bin/env python3
import gi, shutil, subprocess, time, threading, os

# GTK 3 wird für Tray-Icons benötigt (GTK4 hat den Support dafür entfernt/geändert)
gi.require_version('Gtk', '3.0')

# -------------------------------------------------------------------------
# WICHTIG: Automatische Erkennung der AppIndicator Bibliothek
# -------------------------------------------------------------------------
try:
    # Versuch 1: Modernes Ayatana (Standard in Void und vielen neuen Distros)
    gi.require_version('AyatanaAppIndicator3', '0.1')
    from gi.repository import AyatanaAppIndicator3 as AppIndicator
except ValueError:
    try:
        # Versuch 2: Altes AppIndicator3 (Fallback)
        gi.require_version('AppIndicator3', '0.1')
        from gi.repository import AppIndicator3 as AppIndicator
    except ValueError:
        print("FEHLER: Keine AppIndicator-Bibliothek gefunden.")
        print("Bitte installiere 'libayatana-appindicator' (empfohlen) oder 'libappindicator'.")
        exit(1)

from gi.repository import Gtk, GLib

# Eindeutige ID für das Icon
APP_ID = "void-update-tray"

class UpdateTray:
    def __init__(self):
        # Icon erstellen
        self.indicator = AppIndicator.Indicator.new(
            APP_ID,
            "system-software-update", # Standard Icon
            AppIndicator.IndicatorCategory.APPLICATION_STATUS
        )
        self.indicator.set_status(AppIndicator.IndicatorStatus.ACTIVE)
        self.indicator.set_menu(self.build_menu())
        
        # Erster Check sofort, dann alle 30 Minuten (1800 Sekunden)
        self.check_updates()
        GLib.timeout_add_seconds(1800, self.check_updates)

    def build_menu(self):
        menu = Gtk.Menu()
        
        # Status-Zeile (grau, nicht klickbar)
        self.item_status = Gtk.MenuItem(label="Suche nach Updates...")
        self.item_status.set_sensitive(False)
        menu.append(self.item_status)
        
        menu.append(Gtk.SeparatorMenuItem())

        # Update starten
        item_run = Gtk.MenuItem(label="System Update starten")
        item_run.connect("activate", self.run_update)
        menu.append(item_run)
        
        menu.append(Gtk.SeparatorMenuItem())
        
        # Beenden
        item_quit = Gtk.MenuItem(label="Beenden")
        item_quit.connect("activate", self.quit)
        menu.append(item_quit)
        
        menu.show_all()
        return menu

    def run_update(self, _):
        """Führt das Update in einem Terminal aus."""
        # Befehlskette
        cmd = "xbps-install -Su; flatpak update -y"
        if shutil.which("topgrade"):
            cmd = "topgrade"
            
        # Terminal-Emulator finden
        term = "xterm" # Fallback
        for t in ["gnome-terminal", "konsole", "xfce4-terminal", "kitty", "alacritty", "xterm"]:
            if shutil.which(t):
                term = t
                break
        
        # Root-Rechte anfordern (pkexec für GUI, sudo für CLI)
        prefix = ""
        if os.geteuid() != 0:
            if shutil.which("pkexec"): prefix = "pkexec "
            elif shutil.which("sudo"): prefix = "sudo "
            
        # Befehl zusammenbauen: Update ausführen, dann warten (read) damit das Fenster offen bleibt
        full_cmd = f"{prefix}{cmd}; echo; echo '--------------------------------'; read -n 1 -s -r -p 'Fertig. Taste drücken zum Schließen...' || true"
        
        # Terminal mit Befehl starten
        try:
            if term == "gnome-terminal":
                subprocess.Popen([term, "--", "bash", "-c", full_cmd])
            elif term == "konsole":
                subprocess.Popen([term, "-e", "bash", "-c", full_cmd])
            elif term == "xfce4-terminal":
                subprocess.Popen([term, "--hold", "-e", f"bash -c \"{full_cmd}\""])
            else:
                # Standard für xterm, kitty, alacritty
                subprocess.Popen([term, "-e", "bash", "-c", full_cmd])
        except Exception as e:
            print(f"Fehler beim Starten des Terminals: {e}")

    def quit(self, _):
        Gtk.main_quit()

    def check_updates(self):
        """Startet den Update-Check im Hintergrund."""
        threading.Thread(target=self._check_thread, daemon=True).start()
        return True # Damit der GLib Timer weiterläuft

    def _check_thread(self):
        has_xbps = False
        has_flatpak = False
        
        # 1. XBPS Check (Dry run update mit Memory Mode -M)
        # Das prüft gegen den lokalen Cache oder holt Infos ohne Root-Schreibzugriff
        try:
            # Wir nutzen -Mun (Memory, Update, Dry-run). Das zeigt an, was getan WÜRDE.
            # Wenn Output > 0, gibt es Updates.
            # Hinweis: Damit das akkurat ist, muss der User ab und zu syncen oder wir machen 'xbps-install -S' (braucht root).
            # Für Tray Icon ist -M oft "gut genug" oder wir akzeptieren, dass root angefordert wird.
            # Um Root-Passwort-Prompt im Hintergrund zu vermeiden, nutzen wir nur lokalen Check (-n).
            res = subprocess.run(["xbps-install", "-nun"], capture_output=True, text=True)
            if res.returncode == 0 and len(res.stdout.strip()) > 0:
                has_xbps = True
        except: pass

        # 2. Flatpak Check
        if shutil.which("flatpak"):
            try:
                res = subprocess.run(["flatpak", "remote-ls", "--updates"], capture_output=True, text=True)
                if res.returncode == 0 and len(res.stdout.strip()) > 0:
                    has_flatpak = True
            except: pass

        # Ergebnis an UI-Thread übergeben
        GLib.idle_add(self._update_icon, has_xbps, has_flatpak)

    def _update_icon(self, xbps, flatpak):
        if xbps or flatpak:
            # Icon ändern auf "Update verfügbar" (oft orange/rot oder mit Pfeil)
            self.indicator.set_icon_full("software-update-available", "Updates verfügbar")
            
            txt = []
            if xbps: txt.append("System")
            if flatpak: txt.append("Flatpak")
            self.item_status.set_label(f"Updates: {', '.join(txt)}")
        else:
            # Icon ändern auf "Alles aktuell"
            self.indicator.set_icon_full("system-software-update", "System aktuell")
            self.item_status.set_label("System ist aktuell")

if __name__ == "__main__":
    # Signalbehandlung für STRG+C im Terminal
    import signal
    signal.signal(signal.SIGINT, signal.SIG_DFL)
    
    try:
        app = UpdateTray()
        Gtk.main()
    except KeyboardInterrupt:
        pass
