#!/usr/bin/env python3
#--------------------------------------------------------------------------------------------------------
# Name: Linux Lite - Lite System Report
# Architecture: amd64
# Author: Jerry Bezencon
# Website: https://www.linuxliteos.com
# Language: Python/GTK4
# Licence: GPLv2
#--------------------------------------------------------------------------------------------------------

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

import subprocess
import os
import sys
import socket
import platform
import tempfile
import threading
from datetime import datetime
from pathlib import Path
from html import escape


class SystemInfo:
    """Collects system information using various commands."""
    
    def __init__(self):
        self.is_virtual = self._check_hypervisor()
        self.hostname = socket.gethostname()
        self.username = os.environ.get('SUDO_USER', os.environ.get('USER', 'unknown'))
        
    def _run_command(self, cmd, shell=False):
        """Run a command and return its output."""
        try:
            result = subprocess.run(
                cmd if shell else cmd.split(),
                capture_output=True,
                text=True,
                timeout=15,  # Reduced timeout to catch hanging commands
                shell=shell
            )
            return result.stdout.strip()
        except subprocess.TimeoutExpired:
            return "[Command timed out]"
        except (subprocess.SubprocessError, FileNotFoundError):
            return ""
    
    def _check_hypervisor(self):
        """Check if running in a virtual machine."""
        output = self._run_command("systemd-detect-virt")
        return output and output != "none"
    
    def get_install_date(self):
        """Get filesystem creation date."""
        try:
            # Find root mount point
            output = self._run_command("findmnt -no SOURCE /")
            if output:
                tune2fs = self._run_command(f"tune2fs -l {output}")
                for line in tune2fs.split('\n'):
                    if 'Filesystem created' in line:
                        return line.split(':', 1)[1].strip()
        except Exception:
            pass
        return "Unknown"
    
    def get_bios_info(self):
        """Get BIOS information."""
        return self._run_command("dmidecode -t 0")
    
    def get_motherboard_info(self):
        """Get motherboard information."""
        return self._run_command("dmidecode -t 2")
    
    def get_chassis_info(self):
        """Get chassis information."""
        return self._run_command("dmidecode -t 3")
    
    def get_cpu_info(self):
        """Get CPU information."""
        return self._run_command("lscpu")
    
    def get_ram_info(self):
        """Get RAM information."""
        if self.is_virtual:
            return "RAM details not available in Virtual Machine"
        return self._run_command("dmidecode -t 17")
    
    def get_ram_speed(self):
        """Get RAM speed."""
        if self.is_virtual:
            return "Not available in Virtual Machine"
        output = self._run_command("dmidecode --type 17")
        for line in output.split('\n'):
            if 'Speed:' in line and 'Unknown' not in line:
                return line.strip()
        return "Unknown"
    
    def get_graphics_info(self):
        """Get graphics information."""
        # Try lspci first (faster and more reliable)
        info = []
        vga_info = self._run_command("lspci | grep -iE 'vga|3d|display'", shell=True)
        if vga_info:
            info.append("=== Graphics Controllers ===\n")
            info.append(vga_info)
        
        # Try glxinfo for driver info
        glx_info = self._run_command("glxinfo | grep -iE 'vendor|renderer|version' | head -10", shell=True)
        if glx_info:
            info.append("\n\n=== OpenGL Info ===\n")
            info.append(glx_info)
        
        return '\n'.join(info) if info else "No graphics information available"
    
    def get_sound_info(self):
        """Get sound device information."""
        return self._run_command("aplay --list-devices")
    
    def get_hdd_info(self):
        """Get hard drive information."""
        info = []
        info.append("=== File Systems ===\n")
        info.append(self._run_command("df -Th"))
        info.append("\n\n=== Block Devices ===\n")
        info.append(self._run_command("lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT"))
        info.append("\n\n=== Mount Points ===\n")
        info.append(self._run_command("mount"))
        return '\n'.join(info)
    
    def get_network_info(self):
        """Get network information."""
        info = []
        info.append("=== IP Addresses ===\n")
        info.append(self._run_command("ip addr"))
        info.append("\n\n=== Network Devices ===\n")
        # Use lspci instead of lshw for reliability
        net_devices = self._run_command("lspci | grep -iE 'network|ethernet|wireless|wifi'", shell=True)
        if net_devices:
            info.append(net_devices)
        else:
            info.append(self._run_command("ip link show"))
        return '\n'.join(info)
    
    def get_pci_info(self):
        """Get PCI device information."""
        prefix = "[Virtual Machine PCI Information]\n\n" if self.is_virtual else ""
        return prefix + self._run_command("lspci")
    
    def get_usb_info(self):
        """Get USB device information."""
        prefix = "[Virtual Machine USB Information]\n\n" if self.is_virtual else ""
        return prefix + self._run_command("lsusb")
    
    def get_kernel_modules(self):
        """Get loaded kernel modules."""
        return self._run_command("lsmod")
    
    def get_kernel_os_info(self):
        """Get kernel and OS information."""
        info = []
        info.append(self._run_command("lsb_release -a"))
        info.append(f"\nKernel: {platform.release()}")
        info.append(f"Architecture: {platform.machine()}")
        return '\n'.join(info)
    
    def get_groups_info(self):
        """Get user groups information."""
        return self._run_command(f"groups {self.username}")
    
    def get_environment_info(self):
        """Get environment variables."""
        return self._run_command("printenv")
    
    def get_software_info(self):
        """Get installed software information."""
        # Try dpkg first (Debian/Ubuntu), then rpm (Fedora/RHEL), then pacman (Arch)
        output = self._run_command("dpkg --list")
        if output:
            return output
        output = self._run_command("rpm -qa")
        if output:
            return output
        output = self._run_command("pacman -Q")
        if output:
            return output
        return "Package manager not detected"
    
    def get_sources_info(self):
        """Get software sources information."""
        sources = []
        sources_dir = Path("/etc/apt/sources.list.d")
        sources_file = Path("/etc/apt/sources.list")
        
        if sources_file.exists():
            try:
                with open(sources_file) as f:
                    for line in f:
                        if line.strip().startswith('deb'):
                            sources.append(line.strip())
            except PermissionError:
                sources.append("Permission denied reading sources.list")
        
        if sources_dir.exists():
            for f in sources_dir.glob("*.list"):
                try:
                    with open(f) as file:
                        for line in file:
                            if line.strip().startswith('deb'):
                                sources.append(f"{f.name}: {line.strip()}")
                except PermissionError:
                    sources.append(f"Permission denied reading {f.name}")
        
        return '\n'.join(sources) if sources else "No APT sources found (may be using different package manager)"
    
    def get_systemd_info(self):
        """Get systemd information."""
        info = []
        info.append("=== Boot Time Analysis ===\n")
        info.append(self._run_command("systemd-analyze time"))
        info.append("\n\n=== Critical Chain ===\n")
        info.append(self._run_command("systemd-analyze critical-chain"))
        info.append("\n\n=== Enabled Services ===\n")
        info.append(self._run_command("systemctl list-unit-files --type=service --state=enabled"))
        return '\n'.join(info)


class HTMLReportGenerator:
    """Generates HTML reports from system information."""
    
    CSS = """
    :root {
        color-scheme: light dark;
    }
    body {
        font-family: 'Cantarell', 'Segoe UI', system-ui, sans-serif;
        background: #fafafa;
        color: #333;
        margin: 0;
        padding: 20px;
        line-height: 1.6;
    }
    @media (prefers-color-scheme: dark) {
        body { background: #1e1e1e; color: #e0e0e0; }
        .section { background: #2d2d2d; border-color: #444; }
        .section-header { background: #3584e4; }
        table { border-color: #444; }
        th { background: #3d3d3d; }
        tr:nth-child(even) { background: #353535; }
        hr { border-color: #444; }
    }
    .header {
        text-align: center;
        padding: 20px;
        margin-bottom: 20px;
    }
    .header h1 {
        color: #3584e4;
        margin: 0;
        font-size: 2em;
    }
    .meta {
        color: #666;
        margin-top: 10px;
    }
    @media (prefers-color-scheme: dark) {
        .meta { color: #999; }
    }
    .section {
        background: white;
        border-radius: 12px;
        margin-bottom: 16px;
        overflow: hidden;
        border: 1px solid #ddd;
        box-shadow: 0 1px 3px rgba(0,0,0,0.1);
    }
    .section-header {
        background: #3584e4;
        color: white;
        padding: 12px 16px;
        font-weight: bold;
        font-size: 1.1em;
    }
    .section-content {
        padding: 16px;
    }
    .subsection {
        margin-bottom: 16px;
    }
    .subsection-title {
        font-weight: bold;
        color: #3584e4;
        margin-bottom: 8px;
        padding-bottom: 4px;
        border-bottom: 2px solid #3584e4;
    }
    pre {
        background: #f5f5f5;
        padding: 12px;
        border-radius: 8px;
        overflow-x: auto;
        font-family: 'Source Code Pro', 'Consolas', monospace;
        font-size: 0.9em;
        white-space: pre-wrap;
        word-wrap: break-word;
    }
    @media (prefers-color-scheme: dark) {
        pre { background: #1a1a1a; }
    }
    table {
        width: 100%;
        border-collapse: collapse;
        margin-top: 8px;
    }
    th, td {
        padding: 8px 12px;
        text-align: left;
        border-bottom: 1px solid #ddd;
    }
    th {
        background: #f0f0f0;
        font-weight: bold;
    }
    tr:hover {
        background: rgba(53, 132, 228, 0.1);
    }
    .footer {
        text-align: center;
        padding: 20px;
        color: #666;
        font-size: 0.9em;
    }
    hr {
        border: none;
        border-top: 1px solid #ddd;
        margin: 20px 0;
    }
    """
    
    def __init__(self, distributor="Linux System"):
        self.distributor = distributor
        self.sections = []
        
    def add_section(self, title, content, subsections=None):
        """Add a section to the report."""
        self.sections.append({
            'title': title,
            'content': content,
            'subsections': subsections or []
        })
    
    def _format_content(self, content):
        """Format content for HTML display."""
        if not content:
            return "<p><em>No information available</em></p>"
        return f"<pre>{escape(content)}</pre>"
    
    def generate(self):
        """Generate the complete HTML report."""
        now = datetime.now().strftime("%A, %B %d, %Y at %H:%M:%S")
        year = datetime.now().year
        hostname = socket.gethostname()
        
        html = f"""<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{self.distributor} System Report</title>
    <style>{self.CSS}</style>
</head>
<body>
    <div class="header">
        <h1>🖥️ {self.distributor} System Report</h1>
        <div class="meta">
            <div>Generated: {now}</div>
            <div>Hostname: {hostname}</div>
        </div>
    </div>
    <hr>
"""
        
        for section in self.sections:
            html += f"""
    <div class="section">
        <div class="section-header">{escape(section['title'])}</div>
        <div class="section-content">
"""
            if section['subsections']:
                for sub in section['subsections']:
                    html += f"""
            <div class="subsection">
                <div class="subsection-title">{escape(sub['title'])}</div>
                {self._format_content(sub['content'])}
            </div>
"""
            else:
                html += self._format_content(section['content'])
            
            html += """
        </div>
    </div>
"""
        
        html += f"""
    <hr>
    <div class="footer">
        2012-{year} © {self.distributor} System Report<br>
        Generated with Lite System Report
    </div>
</body>
</html>
"""
        return html


class ReportOption:
    """Represents a report option with its collection function."""
    
    def __init__(self, key, title, collect_func, subsections=None):
        self.key = key
        self.title = title
        self.collect_func = collect_func
        self.subsections = subsections  # List of (title, func) tuples for subsections


class LiteSystemReportApp(Adw.Application):
    """Main application class."""
    
    def __init__(self):
        super().__init__(
            application_id="com.github.litesystemreport",
            flags=Gio.ApplicationFlags.FLAGS_NONE
        )
        self.window = None
        self.system_info = SystemInfo()
        self.report_html = None
        self.temp_file = None
        
        # Define report options
        self.report_options = [
            ReportOption(
                "bios", "BIOS and Motherboard", None,
                subsections=[
                    ("BIOS Information", self.system_info.get_bios_info),
                    ("Motherboard Information", self.system_info.get_motherboard_info),
                    ("Chassis Information", self.system_info.get_chassis_info),
                ]
            ),
            ReportOption("cpu", "CPU", self.system_info.get_cpu_info),
            ReportOption(
                "ram", "Memory (RAM)", None,
                subsections=[
                    ("RAM Speed", self.system_info.get_ram_speed),
                    ("RAM Details", self.system_info.get_ram_info),
                ]
            ),
            ReportOption("graphics", "Graphics", self.system_info.get_graphics_info),
            ReportOption("sound", "Sound", self.system_info.get_sound_info),
            ReportOption("hdd", "Hard Drive/SSD/NVME", self.system_info.get_hdd_info),
            ReportOption("network", "Network", self.system_info.get_network_info),
            ReportOption("pci", "PCI Devices", self.system_info.get_pci_info),
            ReportOption("usb", "USB Devices", self.system_info.get_usb_info),
            ReportOption("kernel_modules", "Kernel Modules", self.system_info.get_kernel_modules),
            ReportOption("kernel_os", "Kernel and OS", self.system_info.get_kernel_os_info),
            ReportOption("groups", "User Groups", self.system_info.get_groups_info),
            ReportOption("environment", "Environment Variables", self.system_info.get_environment_info),
            ReportOption("software", "Installed Software", self.system_info.get_software_info),
            ReportOption("sources", "Software Sources", self.system_info.get_sources_info),
            ReportOption("systemd", "SystemD", self.system_info.get_systemd_info),
        ]
        
        self.checkboxes = {}
    
    def _apply_css(self):
        css = b"""
        .dark-text { color: #1e1e1e; }
        .dim-label { opacity: 0.75; }
        """
        provider = Gtk.CssProvider()
        provider.load_from_data(css)
        Gtk.StyleContext.add_provider_for_display(
            Gdk.Display.get_default(), provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )

    def do_activate(self):
        """Activate the application."""
        self._apply_css()
        if not self.window:
            self.window = self.create_window()
        self.window.present()
    
    def create_window(self):
        """Create the main application window."""
        window = Adw.ApplicationWindow(application=self)
        window.set_title("Lite System Report")
        window.set_icon_name("lite-systemreport")
        window.set_default_size(500, 900)
        
        # Main layout
        main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        window.set_content(main_box)
        
        # Header bar
        header = Adw.HeaderBar()
        main_box.append(header)
        
        # About button
        about_btn = Gtk.Button(icon_name="help-about")
        about_btn.connect("clicked", self.on_about_clicked)
        header.pack_start(about_btn)
        
        # Scrolled content
        scrolled = Gtk.ScrolledWindow()
        scrolled.set_vexpand(True)
        scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        main_box.append(scrolled)
        
        # Content clamp for proper width
        clamp = Adw.Clamp()
        clamp.set_maximum_size(600)
        clamp.set_margin_start(12)
        clamp.set_margin_end(12)
        clamp.set_margin_top(12)
        clamp.set_margin_bottom(12)
        scrolled.set_child(clamp)
        
        content_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
        clamp.set_child(content_box)
        
        # Centered header
        title_label = Gtk.Label(label="System Report Generator")
        title_label.add_css_class("title-1")
        title_label.add_css_class("dark-text")
        title_label.set_halign(Gtk.Align.CENTER)
        content_box.append(title_label)

        desc_label = Gtk.Label(label="Select sections to include in the HTML report")
        desc_label.add_css_class("dim-label")
        desc_label.add_css_class("dark-text")
        desc_label.set_halign(Gtk.Align.CENTER)
        desc_label.set_margin_bottom(12)
        content_box.append(desc_label)
        
        # Centered hostname info
        hostname_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
        hostname_box.set_halign(Gtk.Align.CENTER)
        hostname_box.append(Gtk.Image(icon_name="computer"))
        
        hostname_label = Gtk.Label(label=f"Hostname: {self.system_info.hostname}")
        hostname_label.add_css_class("dark-text")
        hostname_box.append(hostname_label)
        content_box.append(hostname_box)
        
        if self.system_info.is_virtual:
            vm_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
            vm_box.set_halign(Gtk.Align.CENTER)
            vm_box.append(Gtk.Image(icon_name="dialog-warning-symbolic"))
            
            vm_label = Gtk.Label(label="Virtual Machine Detected - Some hardware information may be limited")
            vm_label.add_css_class("dim-label")
            vm_box.append(vm_label)
            content_box.append(vm_box)
        
        # Action buttons (below hostname)
        button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12)
        button_box.set_halign(Gtk.Align.CENTER)
        button_box.set_margin_top(12)
        button_box.set_margin_bottom(12)
        content_box.append(button_box)
        
        # Generate button
        generate_btn = Gtk.Button(label="Generate Report")
        generate_btn.add_css_class("suggested-action")
        generate_btn.add_css_class("pill")
        generate_btn.connect("clicked", self.on_generate_clicked)
        button_box.append(generate_btn)
        
        # Quit button
        quit_btn = Gtk.Button(label="Quit")
        quit_btn.add_css_class("pill")
        quit_btn.connect("clicked", lambda b: self.quit())
        button_box.append(quit_btn)
        
        # Options group
        options_group = Adw.PreferencesGroup()
        options_group.set_title("Report Sections")
        content_box.append(options_group)
        
        # Select all row
        select_all_row = Adw.ActionRow()
        select_all_row.set_title("Select All")
        select_all_row.set_subtitle("Toggle all report sections")
        
        select_all_switch = Gtk.Switch()
        select_all_switch.set_active(True)
        select_all_switch.set_valign(Gtk.Align.CENTER)
        select_all_switch.connect("notify::active", self.on_select_all_toggled)
        select_all_row.add_suffix(select_all_switch)
        select_all_row.set_activatable_widget(select_all_switch)
        options_group.add(select_all_row)
        
        self.select_all_switch = select_all_switch
        
        # Add checkboxes for each option
        for option in self.report_options:
            row = Adw.ActionRow()
            row.set_title(option.title)
            row.set_use_underline(False)
            
            # Add icon based on category
            icon_map = {
                "bios": "application-x-firmware-symbolic",
                "cpu": "speedometer-symbolic",
                "ram": "memory-symbolic",
                "graphics": "video-display-symbolic",
                "sound": "audio-card-symbolic",
                "hdd": "drive-harddisk-symbolic",
                "network": "network-wired-symbolic",
                "pci": "expansion-card-symbolic",
                "usb": "media-removable-symbolic",
                "kernel_modules": "system-run-symbolic",
                "kernel_os": "emblem-system-symbolic",
                "groups": "system-users-symbolic",
                "environment": "preferences-system-symbolic",
                "software": "system-software-install-symbolic",
                "sources": "emblem-documents-symbolic",
                "systemd": "preferences-other-symbolic",
            }
            icon_name = icon_map.get(option.key, "emblem-system-symbolic")
            icon = Gtk.Image(icon_name=icon_name)
            icon.set_icon_size(Gtk.IconSize.NORMAL)
            row.add_prefix(icon)
            
            check = Gtk.CheckButton()
            check.set_active(True)
            check.set_valign(Gtk.Align.CENTER)
            row.add_suffix(check)
            row.set_activatable_widget(check)
            
            self.checkboxes[option.key] = check
            options_group.add(row)
        
        return window
    
    def on_select_all_toggled(self, switch, _):
        """Toggle all checkboxes."""
        active = switch.get_active()
        for check in self.checkboxes.values():
            check.set_active(active)
    
    def open_url(self, url):
        """Open URL in user's default browser."""
        sudo_user = os.environ.get('SUDO_USER')
        
        try:
            if sudo_user and os.geteuid() == 0:
                import pwd
                uid = pwd.getpwnam(sudo_user).pw_uid
                dbus_addr = f"unix:path=/run/user/{uid}/bus"
                
                cmd = [
                    'sudo', '-u', sudo_user,
                    'env', f'DBUS_SESSION_BUS_ADDRESS={dbus_addr}',
                    'xdg-open', url
                ]
            else:
                cmd = ['xdg-open', url]
            
            subprocess.Popen(cmd,
                           stdout=subprocess.DEVNULL,
                           stderr=subprocess.DEVNULL,
                           start_new_session=True)
        except Exception:
            pass

    def on_about_clicked(self, button):
        """Show about dialog."""
        about = Adw.AboutWindow(
            transient_for=self.window,
            application_name="Lite System Report",
            application_icon="computer-symbolic",
            developer_name="Jerry Bezencon - Linux Lite",
            license_type=Gtk.License.UNKNOWN,
            website="https://www.linuxliteos.com",
            issue_url="https://gitlab.com/linuxlite/litesoftware",
        )
        about.add_credit_section("Developer", ["Jerry Bezencon <valtam@linuxliteos.com>"])
        about.add_link("Licence", "https://www.gnu.org/licenses/old-licenses/gpl-2.0.html")
        
        # Handle link clicks to open as actual user
        about.connect("activate-link", self.on_about_link_clicked)
        about.present()
    
    def on_about_link_clicked(self, widget, uri):
        """Handle link clicks in About dialog."""
        self.open_url(uri)
        return True  # Prevent default handler
    
    def on_generate_clicked(self, button):
        """Generate the report."""
        # Get selected options
        selected = [opt for opt in self.report_options if self.checkboxes[opt.key].get_active()]
        
        if not selected:
            dialog = Adw.MessageDialog(
                transient_for=self.window,
                heading="No Sections Selected",
                body="Please select at least one section to include in the report.",
            )
            dialog.add_response("ok", "OK")
            dialog.set_default_response("ok")
            dialog.present()
            return
        
        # Show progress dialog
        progress_dialog = Adw.MessageDialog(
            transient_for=self.window,
            heading="Generating Report",
            body="Collecting system information...",
        )
        
        spinner = Gtk.Spinner()
        spinner.set_size_request(32, 32)
        spinner.start()
        progress_dialog.set_extra_child(spinner)
        progress_dialog.present()
        
        # Run generation in background thread
        def generate_thread():
            try:
                generator = HTMLReportGenerator("Linux System")
                
                for i, option in enumerate(selected):
                    # Update progress
                    GLib.idle_add(
                        progress_dialog.set_body,
                        f"Collecting {option.title}... ({i+1}/{len(selected)})"
                    )
                    
                    if option.subsections:
                        subsections = []
                        for sub_title, sub_func in option.subsections:
                            content = sub_func()
                            subsections.append({'title': sub_title, 'content': content})
                        generator.add_section(option.title, None, subsections)
                    else:
                        content = option.collect_func()
                        generator.add_section(option.title, content)
                
                self.report_html = generator.generate()
                
                # Save to temp file
                fd, self.temp_file = tempfile.mkstemp(suffix='.html', prefix='sysreport-')
                with os.fdopen(fd, 'w') as f:
                    f.write(self.report_html)
                
                # Make temp file readable by everyone (so browser can access it)
                os.chmod(self.temp_file, 0o644)
                
                GLib.idle_add(self.show_report_dialog, progress_dialog)
                
            except Exception as e:
                GLib.idle_add(self.show_error, progress_dialog, str(e))
        
        thread = threading.Thread(target=generate_thread)
        thread.daemon = True
        thread.start()
    
    def show_error(self, progress_dialog, error_msg):
        """Show error dialog."""
        progress_dialog.close()
        
        dialog = Adw.MessageDialog(
            transient_for=self.window,
            heading="Error Generating Report",
            body=f"An error occurred: {error_msg}",
        )
        dialog.add_response("ok", "OK")
        dialog.present()
    
    def show_report_dialog(self, progress_dialog):
        """Show the generated report."""
        progress_dialog.close()
        
        # Create report viewer window
        report_window = Adw.Window(transient_for=self.window)
        report_window.set_title("System Report")
        report_window.set_default_size(900, 700)
        report_window.set_modal(True)
        
        # Toast overlay for notifications
        toast_overlay = Adw.ToastOverlay()
        report_window.set_content(toast_overlay)
        
        # Main layout
        main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        toast_overlay.set_child(main_box)
        
        # Header bar with actions
        header = Adw.HeaderBar()
        main_box.append(header)
        
        # Save button
        save_btn = Gtk.Button(icon_name="document-save-symbolic")
        save_btn.set_tooltip_text("Save Report")
        save_btn.connect("clicked", lambda b: self.save_report(toast_overlay))
        header.pack_start(save_btn)
        
        # Save to Desktop button
        desktop_btn = Gtk.Button(icon_name="user-desktop-symbolic")
        desktop_btn.set_tooltip_text("Save to Desktop")
        desktop_btn.connect("clicked", lambda b: self.save_to_desktop(toast_overlay))
        header.pack_start(desktop_btn)
        
        # Open in browser button
        browser_btn = Gtk.Button(icon_name="web-browser-symbolic")
        browser_btn.set_tooltip_text("Open in Browser")
        browser_btn.connect("clicked", lambda b: self.open_in_browser())
        header.pack_end(browser_btn)
        
        # WebKit view or fallback text view
        try:
            gi.require_version('WebKit', '6.0')
            from gi.repository import WebKit
            
            webview = WebKit.WebView()
            webview.load_html(self.report_html, "file:///")
            webview.set_vexpand(True)
            main_box.append(webview)
        except (ValueError, ImportError):
            # Fallback to text view if WebKit not available
            scrolled = Gtk.ScrolledWindow()
            scrolled.set_vexpand(True)
            main_box.append(scrolled)
            
            text_view = Gtk.TextView()
            text_view.set_editable(False)
            text_view.set_wrap_mode(Gtk.WrapMode.WORD)
            text_view.get_buffer().set_text(
                "WebKit not available. Report saved to:\n\n"
                f"{self.temp_file}\n\n"
                "Click 'Open in Browser' to view the report."
            )
            text_view.set_margin_start(12)
            text_view.set_margin_end(12)
            text_view.set_margin_top(12)
            text_view.set_margin_bottom(12)
            scrolled.set_child(text_view)
        
        report_window.present()
    
    def save_report(self, toast_overlay):
        """Save report to user-selected location."""
        dialog = Gtk.FileDialog()
        dialog.set_title("Save System Report")
        
        # Set default filename
        timestamp = datetime.now().strftime("%Y-%m-%d_%H%M%S")
        dialog.set_initial_name(f"sysreport-{timestamp}.html")
        
        # Set initial folder to actual user's home directory
        sudo_user = os.environ.get('SUDO_USER')
        if sudo_user:
            initial_folder = Gio.File.new_for_path(f"/home/{sudo_user}")
            dialog.set_initial_folder(initial_folder)
        
        # Set filter
        filter_html = Gtk.FileFilter()
        filter_html.set_name("HTML files")
        filter_html.add_mime_type("text/html")
        filter_html.add_pattern("*.html")
        
        filters = Gio.ListStore.new(Gtk.FileFilter)
        filters.append(filter_html)
        dialog.set_filters(filters)
        dialog.set_default_filter(filter_html)
        
        def on_save_response(dialog, result):
            try:
                file = dialog.save_finish(result)
                if file:
                    path = file.get_path()
                    with open(path, 'w') as f:
                        f.write(self.report_html)
                    # Change ownership to actual user
                    sudo_user = os.environ.get('SUDO_USER')
                    if sudo_user:
                        import pwd
                        uid = pwd.getpwnam(sudo_user).pw_uid
                        gid = pwd.getpwnam(sudo_user).pw_gid
                        os.chown(path, uid, gid)
                    self.show_toast(toast_overlay, f"Report saved to {path}")
            except GLib.Error as e:
                if e.code != Gtk.DialogError.DISMISSED:
                    self.show_toast(toast_overlay, f"Error saving: {e.message}")
        
        dialog.save(self.window, None, on_save_response)
    
    def save_to_desktop(self, toast_overlay):
        """Save report to Desktop."""
        # Get actual user's home directory (not root's)
        sudo_user = os.environ.get('SUDO_USER')
        if sudo_user:
            desktop = Path(f"/home/{sudo_user}/Desktop")
            home = Path(f"/home/{sudo_user}")
        else:
            desktop = Path.home() / "Desktop"
            home = Path.home()
        
        if not desktop.exists():
            desktop = home
        
        timestamp = datetime.now().strftime("%Y-%m-%d_%H%M%S")
        path = desktop / f"sysreport-{timestamp}.html"
        
        try:
            with open(path, 'w') as f:
                f.write(self.report_html)
            # Change ownership to actual user
            if sudo_user:
                import pwd
                uid = pwd.getpwnam(sudo_user).pw_uid
                gid = pwd.getpwnam(sudo_user).pw_gid
                os.chown(path, uid, gid)
            self.show_toast(toast_overlay, f"Saved to {path}")
        except Exception as e:
            self.show_toast(toast_overlay, f"Error: {e}")
    
    def open_in_browser(self):
        """Open report in default browser."""
        if self.temp_file:
            self.open_url(f"file://{self.temp_file}")
    
    def show_toast(self, toast_overlay, message):
        """Show a toast notification."""
        toast = Adw.Toast(title=message)
        toast.set_timeout(3)
        toast_overlay.add_toast(toast)


def check_and_elevate():
    """Re-exec via pkexec if not running as root."""
    if os.geteuid() != 0:
        script_path = os.path.abspath(__file__)
        try:
            os.execvp('pkexec', ['pkexec', script_path] + sys.argv[1:])
        except Exception as e:
            print(f"Failed to elevate privileges: {e}", file=sys.stderr)
            sys.exit(1)


def main():
    """Main entry point."""
    # Elevate to root using existing polkit policy
    check_and_elevate()
    
    app = LiteSystemReportApp()
    return app.run(None)


if __name__ == "__main__":
    main()
