#!/usr/bin/env python3
#--------------------------------------------------------------------------------------------------------
# Name: Linux Lite - Lite Firewall Config
# 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, GLib, Gio, Gdk
import subprocess
import threading

# Icon paths
ICON_ENABLED = "/usr/share/icons/Papirus/22x22/apps/security-high.svg"
ICON_DISABLED = "/usr/share/icons/Papirus/22x22/apps/security-low.svg"
ICON_INFO = "/usr/share/icons/Papirus/22x22/status/dialog-information.svg"
ICON_APP = "/usr/share/icons/Papirus/24x24/apps/lite-firewallconfig.png"


def run_helper(action):
    """Invoke the privileged lite-firewallconfig-helper via pkexec. The helper
    script has its own polkit policy (com.linuxliteos.lite-firewallconfig) so
    the auth dialog shows the LL shield icon and a clean message rather than
    the generic 'Authentication is needed to run /bin/sh' text.
    Returns (success, stderr)."""
    try:
        result = subprocess.run(
            ["pkexec", "/usr/bin/lite-firewallconfig-helper", action],
            capture_output=True, text=True, timeout=60
        )
        return result.returncode == 0, (result.stderr or "").strip()
    except subprocess.TimeoutExpired:
        return False, "pkexec timed out"
    except Exception as e:
        return False, str(e)


class ProgressDialog(Gtk.Window):
    """An indeterminate-progress dialog shown while a pkexec call runs."""

    def __init__(self, parent, title, label):
        super().__init__(title=title)
        self.set_transient_for(parent)
        self.set_modal(True)
        self.set_default_size(400, 100)
        self.set_resizable(False)

        self.success = False
        self.error_detail = ""
        self._pulse_source = None

        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
        box.set_margin_top(20)
        box.set_margin_bottom(20)
        box.set_margin_start(20)
        box.set_margin_end(20)

        self.status_label = Gtk.Label(label=label)
        self.status_label.set_xalign(0)
        box.append(self.status_label)

        self.progress_bar = Gtk.ProgressBar()
        box.append(self.progress_bar)

        self.set_child(box)

    def run_action(self, action, on_complete):
        """Invoke pkexec /usr/bin/lite-firewallconfig-helper <action>, pulsing
        the bar while it runs."""
        self._pulse_source = GLib.timeout_add(100, self._pulse)

        def worker():
            self.success, self.error_detail = run_helper(action)
            GLib.idle_add(self.on_finished, on_complete)

        thread = threading.Thread(target=worker, daemon=True)
        thread.start()

    def _pulse(self):
        self.progress_bar.pulse()
        return True

    def on_finished(self, callback):
        if self._pulse_source is not None:
            GLib.source_remove(self._pulse_source)
            self._pulse_source = None
        self.close()
        if callback:
            callback(self.success, self.error_detail)
        return False


class FirewallConfigApp(Adw.Application):
    """Main FirewallD configuration application."""
    
    def __init__(self):
        super().__init__(application_id="com.linuxlite.firewallconfig",
                         flags=Gio.ApplicationFlags.FLAGS_NONE)
        self.window = None
        
    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):
        """Create and show the main window."""
        self._apply_css()
        if self.window is None:
            self.window = Adw.ApplicationWindow(application=self)
            self.window.set_title("Firewall")
            self.window.set_default_size(280, 200)
            self.window.set_resizable(False)
            
            # Try to set window icon
            try:
                self.window.set_icon_name("lite-firewallconfig")
            except:
                pass
            
            # Main container
            main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
            
            # Header bar
            header = Adw.HeaderBar()
            header.set_show_end_title_buttons(True)
            main_box.append(header)
            
            # Content box
            content_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
            content_box.set_margin_top(20)
            content_box.set_margin_bottom(20)
            content_box.set_margin_start(20)
            content_box.set_margin_end(20)
            content_box.set_halign(Gtk.Align.CENTER)
            content_box.set_valign(Gtk.Align.CENTER)
            content_box.set_vexpand(True)
            
            # Enable Firewall button
            enable_btn = self.create_button("Enable Firewall", ICON_ENABLED,
                                            self.on_enable_clicked)
            content_box.append(enable_btn)
            
            # Disable Firewall button
            disable_btn = self.create_button("Disable Firewall", ICON_DISABLED,
                                             self.on_disable_clicked)
            content_box.append(disable_btn)
            
            # Show Status button
            status_btn = self.create_button("Show Status", ICON_INFO,
                                            self.on_status_clicked)
            content_box.append(status_btn)
            
            main_box.append(content_box)
            self.window.set_content(main_box)
        
        self.window.present()
    
    def create_button(self, label, icon_path, callback):
        """Create a button with an icon."""
        button = Gtk.Button()
        button.set_size_request(200, 40)
        
        box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
        box.set_halign(Gtk.Align.CENTER)
        
        # Try to load icon from file, fall back to symbolic icon
        try:
            icon = Gtk.Image.new_from_file(icon_path)
        except:
            icon = Gtk.Image.new_from_icon_name("dialog-information-symbolic")
        icon.set_pixel_size(22)
        
        label_widget = Gtk.Label(label=label)
        label_widget.add_css_class("dark-text")

        box.append(icon)
        box.append(label_widget)
        button.set_child(box)
        button.connect("clicked", callback)
        
        return button
    
    def on_enable_clicked(self, button):
        """Enable the firewall via the pkexec'd helper."""
        dialog = ProgressDialog(self.window, "Firewall — Enable", "Enabling Firewall...")
        dialog.present()
        dialog.run_action("enable", self._on_enable_done)

    def _on_enable_done(self, success, error_detail):
        if success:
            self.show_message("Firewall Enabled",
                              "The Firewall has been enabled successfully.")
        else:
            body = "Failed to enable the firewall."
            if error_detail:
                body += f"\n\n{error_detail}"
            self.show_message("Error", body)

    def on_disable_clicked(self, button):
        """Disable the firewall via the pkexec'd helper."""
        dialog = ProgressDialog(self.window, "Firewall — Disable", "Disabling Firewall...")
        dialog.present()
        dialog.run_action("disable", self._on_disable_done)

    def _on_disable_done(self, success, error_detail):
        if success:
            self.show_message("Firewall Disabled",
                              "The Firewall has been disabled successfully.")
        else:
            body = "Failed to disable the firewall."
            if error_detail:
                body += f"\n\n{error_detail}"
            self.show_message("Error", body)
    
    def on_status_clicked(self, button):
        """Show the current firewall status."""
        try:
            result = subprocess.run(
                ["systemctl", "is-active", "firewalld"],
                capture_output=True,
                text=True
            )
            is_active = result.stdout.strip() == "active"
        except Exception:
            is_active = False
        
        if is_active:
            status_text = "ENABLED"
        else:
            status_text = "DISABLED"
        
        # Create status dialog
        dialog = Adw.MessageDialog(
            transient_for=self.window,
            modal=True,
            heading="Firewall Status",
        )
        
        # Create styled label for status
        status_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8)
        
        intro_label = Gtk.Label(label="The Firewall is currently:")
        status_box.append(intro_label)
        
        status_label = Gtk.Label()
        status_label.set_markup(
            f"<b><span foreground='{'green' if is_active else 'red'}' "
            f"size='large'>{status_text}</span></b>"
        )
        status_box.append(status_label)
        
        dialog.set_extra_child(status_box)
        dialog.add_response("ok", "OK")
        dialog.set_default_response("ok")
        dialog.present()
    
    def show_message(self, title, message):
        """Show a simple message dialog."""
        dialog = Adw.MessageDialog(
            transient_for=self.window,
            modal=True,
            heading=title,
            body=message
        )
        dialog.add_response("ok", "OK")
        dialog.set_default_response("ok")
        dialog.present()


def main():
    app = FirewallConfigApp()
    return app.run(None)


if __name__ == "__main__":
    main()
