import os
import subprocess
import getpass
import threading
import time

# WICHTIG: Renderer-Fix für Stabilität
os.environ["GSK_RENDERER"] = "ngl"

import gi
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
from gi.repository import Gtk, Adw, Gio, GLib, GObject

try:
    import cups
except ImportError:
    print("Hinweis: python3-cups ist noch nicht installiert.")

class DeviceManager(Adw.Application):
    def __init__(self):
        super().__init__(application_id='org.voidlinux.devicemanager')

    def do_activate(self):
        self.win = Adw.ApplicationWindow(application=self)
        self.win.set_title("Void Print & Scan Manager")
        self.win.set_default_size(750, 750) # Etwas höher für die Icons

        # Overlay für Toasts
        self.toast_overlay = Adw.ToastOverlay()
        
        main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.toast_overlay.set_child(main_box)
        self.win.set_content(self.toast_overlay)

        # View Stack
        self.view_stack = Adw.ViewStack()
        self.view_stack.set_vexpand(True)
        
        # Seiten hinzufügen
        page_setup = self.create_setup_page()
        stack_setup = self.view_stack.add_titled(page_setup, "setup", "System")
        stack_setup.set_icon_name("preferences-system-symbolic")

        page_drivers = self.create_driver_page()
        stack_drivers = self.view_stack.add_titled(page_drivers, "drivers", "Treiber")
        stack_drivers.set_icon_name("printer-symbolic")

        page_apps = self.create_apps_page()
        stack_apps = self.view_stack.add_titled(page_apps, "apps", "Software")
        stack_apps.set_icon_name("applications-system-symbolic")

        # Header
        header = Adw.HeaderBar()
        view_switcher = Adw.ViewSwitcher(stack=self.view_stack)
        header.set_title_widget(view_switcher)
        main_box.append(header)
        main_box.append(self.view_stack)

        self.win.present()

    # --- HELPER: Checks ---
    def is_pkg_installed(self, pkg):
        try:
            subprocess.check_call(["xbps-query", "-S", pkg], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
            return True
        except:
            return False

    def is_service_running(self, svc):
        return os.path.exists(f"/var/service/{svc}")

    def show_toast(self, message):
        toast = Adw.Toast(title=message)
        toast.set_timeout(3)
        self.toast_overlay.add_toast(toast)

    # --- HELPER: DEKORATION (NEU) ---
    def add_bottom_decoration(self, box, icon1_name, icon2_name):
        """Fügt große, dezente Icons am unteren Rand hinzu."""
        
        # Container Box, die den restlichen Platz nach unten drückt
        bottom_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=60)
        bottom_box.set_halign(Gtk.Align.CENTER) # Horizontal mittig
        bottom_box.set_valign(Gtk.Align.END)    # Vertikal ganz unten
        bottom_box.set_vexpand(True)            # Nimmt verfügbaren Platz ein
        bottom_box.set_margin_bottom(40)
        bottom_box.set_margin_top(20)

        # Icon 1
        img1 = Gtk.Image.new_from_icon_name(icon1_name)
        img1.set_pixel_size(128)  # Sehr groß
        img1.set_opacity(0.1)     # Sehr transparent (Wasserzeichen-Effekt)
        bottom_box.append(img1)

        # Icon 2
        img2 = Gtk.Image.new_from_icon_name(icon2_name)
        img2.set_pixel_size(128)
        img2.set_opacity(0.1)
        bottom_box.append(img2)

        box.append(bottom_box)

    # --- SEITEN ---

    def create_setup_page(self):
        scrolled = Gtk.ScrolledWindow()
        scrolled.set_vexpand(True)
        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=15)
        box.set_margin_all(20)

        # 1. Repo Check
        group_repo = Adw.PreferencesGroup(title="1. Repositories & Netzwerk")
        row_repo = Adw.ActionRow(title="Non-Free Repository", subtitle="Für Brother/Canon Treiber benötigt.")
        if self.is_pkg_installed("void-repo-nonfree"):
            row_repo.add_suffix(Gtk.Image.new_from_icon_name("emblem-ok-symbolic"))
        else:
            self.add_install_button(row_repo, ["void-repo-nonfree"])
        group_repo.add(row_repo)

        row_mdns = Adw.ActionRow(title="Netzwerk-Auflösung (mDNS)", subtitle="Paket 'nss-mdns' für Netzwerkdrucker (.local).")
        if self.is_pkg_installed("nss-mdns"):
            row_mdns.add_suffix(Gtk.Image.new_from_icon_name("emblem-ok-symbolic"))
        else:
            self.add_install_button(row_mdns, ["nss-mdns"])
        group_repo.add(row_mdns)
        box.append(group_repo)

        # 2. Firewall
        if self.is_pkg_installed("ufw"):
            group_fw = Adw.PreferencesGroup(title="2. Firewall (UFW)")
            row_fw = Adw.ActionRow(title="Drucker-Ports freigeben", subtitle="Öffnet Port 631 (IPP) und 5353 (mDNS).")
            btn_fw = Gtk.Button(label="Freigeben")
            btn_fw.set_valign(Gtk.Align.CENTER)
            btn_fw.connect("clicked", self.on_fix_firewall)
            row_fw.add_suffix(btn_fw)
            group_fw.add(row_fw)
            box.append(group_fw)

        # 3. System
        group_system = Adw.PreferencesGroup(title="3. Dienste & Rechte")
        
        # Check ob User bereits in Gruppen ist (einfacher Check)
        user = getpass.getuser()
        # Hinweis: Das ist kein perfekter Check, aber gut genug für die UI
        try:
            groups = subprocess.check_output(["groups", user], text=True)
            in_groups = "lp" in groups and "scanner" in groups
        except:
            in_groups = False

        row_prep = Adw.ActionRow(title="Dienste & User-Rechte", subtitle="Startet cupsd/avahi und setzt Gruppenrechte.")
        if in_groups and self.is_service_running("cupsd"):
            row_prep.add_prefix(Gtk.Image.new_from_icon_name("emblem-ok-symbolic"))
        
        btn_prep = Gtk.Button(label="Konfigurieren")
        btn_prep.set_valign(Gtk.Align.CENTER)
        btn_prep.connect("clicked", self.on_prepare_system)
        row_prep.add_suffix(btn_prep)
        group_system.add(row_prep)
        box.append(group_system)

        # 4. Suche
        group_disc = Adw.PreferencesGroup(title="4. Geräte-Suche")
        self.device_list = Gtk.ListBox()
        self.device_list.add_css_class("boxed-list")
        self.add_list_row(self.device_list, "Status", "Bereit zur Suche.")
        group_disc.add(self.device_list)
        box.append(group_disc)

        btn_scan = Gtk.Button(label="Nach Geräten suchen")
        btn_scan.add_css_class("suggested-action")
        btn_scan.connect("clicked", self.on_discover_devices)
        box.append(btn_scan)

        # --- DEKORATION SEITE 1: DRUCKER & SCANNER ---
        self.add_bottom_decoration(box, "printer-symbolic", "scanner-symbolic")

        scrolled.set_child(box)
        return scrolled

    def create_driver_page(self):
        scrolled = Gtk.ScrolledWindow()
        scrolled.set_vexpand(True)
        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=15)
        box.set_margin_all(20)

        group = Adw.PreferencesGroup(title="Hersteller Treiber")
        drivers = {
            "HP": ["hplip", "hplip-gui"],
            "Epson": ["epson-inkjet-printer-escpr", "iscan"],
            "Brother": ["brlaser"],
            "Canon": ["cups-bjnp", "gutenprint"],
            "Samsung": ["splix", "foomatic-db"],
            "Lexmark": ["gutenprint", "foomatic-db"],
            "Generisch": ["gutenprint", "foomatic-db", "cups-filters"]
        }

        for brand, pkgs in drivers.items():
            row = Adw.ActionRow(title=brand, subtitle=f"Pakete: {', '.join(pkgs)}")
            if self.is_pkg_installed(pkgs[0]):
                btn = Gtk.Button(label="Installiert")
                btn.set_sensitive(False)
                row.add_suffix(btn)
            else:
                self.add_install_button(row, pkgs)
            group.add(row)

        box.append(group)
        
        # --- DEKORATION SEITE 2: PAKET & FESTPLATTE ---
        self.add_bottom_decoration(box, "package-x-generic-symbolic", "drive-harddisk-symbolic")

        scrolled.set_child(box)
        return scrolled

    def create_apps_page(self):
        scrolled = Gtk.ScrolledWindow()
        scrolled.set_vexpand(True)
        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=15)
        box.set_margin_all(20)
        group = Adw.PreferencesGroup(title="Anwendungen")

        apps = {
            "Drucker-Verwaltung": ("system-config-printer", ["system-config-printer"]),
            "Simple Scan": ("simple-scan", ["simple-scan"]),
            "XSane": ("xsane", ["xsane"]),
            "Gscan2pdf": ("gscan2pdf", ["gscan2pdf"]),
            "PDF Arranger": ("pdfarranger", ["pdfarranger"]),
            "OCR (Deutsch)": ("tesseract-ocr", ["tesseract-ocr", "tesseract-ocr-deu"])
        }

        for name, info in apps.items():
            desc, pkgs = info
            row = Adw.ActionRow(title=name, subtitle=desc)
            if self.is_pkg_installed(pkgs[0]):
                btn = Gtk.Button(label="Installiert")
                btn.set_sensitive(False)
                row.add_suffix(btn)
            else:
                self.add_install_button(row, pkgs)
            group.add(row)

        box.append(group)
        
        # --- DEKORATION SEITE 3: APPS ---
        self.add_bottom_decoration(box, "system-search-symbolic", "video-display-symbolic")

        scrolled.set_child(box)
        return scrolled

    # --- GUI HELPERS ---

    def add_install_button(self, row, pkgs):
        btn = Gtk.Button(label="Installieren")
        btn.set_valign(Gtk.Align.CENTER)
        btn._pkgs = pkgs 
        btn.connect("clicked", self.on_install_click)
        row.add_suffix(btn)

    def add_list_row(self, listbox, title, sub):
        row = Adw.ActionRow(title=title, subtitle=sub)
        listbox.append(row)

    # --- LOGIC ---

    def run_pkexec(self, cmd):
        try:
            subprocess.run(["pkexec", "sh", "-c", cmd], check=True)
            return True
        except:
            return False

    def on_install_click(self, btn):
        btn.set_sensitive(False)
        btn.set_label("Lade...")
        thread = threading.Thread(target=self.thread_install, args=(btn, btn._pkgs))
        thread.daemon = True
        thread.start()

    def thread_install(self, btn, pkgs):
        pkg_str = " ".join(pkgs)
        success = self.run_pkexec(f"xbps-install -Sy {pkg_str}")
        GLib.idle_add(self.install_finished, btn, success)

    def install_finished(self, btn, success):
        if success:
            btn.set_label("Installiert")
            self.show_toast("Installation erfolgreich!")
        else:
            btn.set_label("Installieren")
            btn.set_sensitive(True)
            self.show_toast("Fehler bei der Installation.")

    def on_fix_firewall(self, btn):
        if self.run_pkexec("ufw allow 631/tcp && ufw allow 5353/udp"):
            self.show_toast("Ports geöffnet.")

    def on_prepare_system(self, btn):
        user = getpass.getuser()
        cmd = f"groupadd -f lp && groupadd -f scanner && groupadd -f lpadmin && " \
              f"usermod -aG lp,scanner,lpadmin {user} && " \
              "ln -sf /etc/sv/cupsd /var/service/ && " \
              "ln -sf /etc/sv/avahi-daemon /var/service/ && " \
              "ln -sf /etc/sv/dbus /var/service/"
        
        if self.run_pkexec(cmd):
            self.show_toast("System konfiguriert! Bitte neu anmelden.")

    def on_discover_devices(self, btn):
        while child := self.device_list.get_first_child():
            self.device_list.remove(child)
        self.add_list_row(self.device_list, "Suche läuft...", "Bitte warten.")
        thread = threading.Thread(target=self.thread_discover)
        thread.daemon = True
        thread.start()

    def thread_discover(self):
        printers = []
        scanners = []
        try:
            conn = cups.Connection()
            for p in conn.getPrinters(): printers.append(p)
        except: printers = None
        
        try:
            res = subprocess.check_output(["scanimage", "-L"], text=True, stderr=subprocess.STDOUT)
            for line in res.split('\n'):
                if "device" in line:
                    scanners.append(line.replace("device ", "").replace("`", "").replace("'", ""))
        except: scanners = None
        GLib.idle_add(self.discovery_finished, printers, scanners)

    def discovery_finished(self, printers, scanners):
        while child := self.device_list.get_first_child():
            self.device_list.remove(child)

        if printers:
            for p in printers: self.add_list_row(self.device_list, f"🖨️ {p}", "CUPS Drucker")
        elif printers is None:
            self.add_list_row(self.device_list, "Fehler", "CUPS nicht aktiv.")
        else:
            self.add_list_row(self.device_list, "Drucker", "Keine gefunden.")

        if scanners:
            for s in scanners: self.add_list_row(self.device_list, "📠 Scanner", s)
        elif scanners is None:
            self.add_list_row(self.device_list, "Fehler", "SANE/Scanner Fehler.")
        else:
            self.add_list_row(self.device_list, "Scanner", "Keine gefunden.")

# Helper Margins
Gtk.Box.set_margin_all = lambda self, val: [
    self.set_margin_top(val), self.set_margin_bottom(val), 
    self.set_margin_start(val), self.set_margin_end(val)
]

if __name__ == "__main__":
    app = DeviceManager()
    app.run()
