#!/usr/bin/env python

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, GLib, Gio, Gdk
import subprocess
import os
import tempfile

class MirrorUpdater(Gtk.ApplicationWindow):
    def __init__(self, app):
        super().__init__(application=app, title="AcreetionOS Mirror Updater")
        self.set_default_size(500, 350)

        # Set Icon using the modern GTK4 approach
        try:
            icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default())
            script_dir = os.path.dirname(os.path.abspath(__file__))
            icon_theme.add_search_path(script_dir)
            self.set_icon_name("acreetionoslogo")
        except Exception as e:
            print(f"Could not set window icon: {e}")

        self.vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
        self.vbox.set_margin_top(12)
        self.vbox.set_margin_bottom(12)
        self.vbox.set_margin_start(12)
        self.vbox.set_margin_end(12)
        self.set_child(self.vbox)

        # --- Header Bar ---
        header = Gtk.HeaderBar()
        self.set_titlebar(header)
        
        # --- Main Content ---
        
        # Add a title label
        title_label = Gtk.Label()
        title_label.set_markup("<span size='large' weight='bold'>Mirror and Configuration Updater</span>")
        self.vbox.append(title_label)


        self.button = Gtk.Button(label=" Start Update Process")
        self.button.connect("clicked", self.on_button_clicked)
        
        # Add an icon to the button
        icon = Gtk.Image.new_from_icon_name("emblem-synchronizing-symbolic")
        self.button.set_child(Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 6))
        self.button.get_child().append(icon)
        self.button.get_child().append(Gtk.Label(label="Start Update Process"))
        self.button.set_halign(Gtk.Align.CENTER)
        self.button.get_style_context().add_class("suggested-action")

        self.vbox.append(self.button)

        # Log view
        self.textview = Gtk.TextView()
        self.textview.set_editable(False)
        self.textview.set_monospace(True)
        self.textview.get_style_context().add_class("view")

        self.scrolled_window = Gtk.ScrolledWindow()
        self.scrolled_window.set_child(self.textview)
        self.scrolled_window.set_vexpand(True)
        self.scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        self.vbox.append(self.scrolled_window)
        
        self.log("Welcome! Click the button to begin.")


    def on_button_clicked(self, widget):
        self.button.set_sensitive(False)
        self.log("Starting update process...")
        
        # Run the update in a separate thread to keep the UI responsive
        GLib.idle_add(self.run_update)

    def log(self, message):
        buffer = self.textview.get_buffer()
        buffer.insert(buffer.get_end_iter(), message + "\n", -1)
        # Autoscroll
        adj = self.scrolled_window.get_vadjustment()
        adj.set_value(adj.get_upper() - adj.get_page_size())


    def run_update(self):
        # Use Zenity to confirm
        confirm_cmd = ["zenity", "--question", "--text=This will download new mirrorlist and pacman.conf files and install them. Do you want to continue?", "--width=300"]
        try:
            subprocess.run(confirm_cmd, check=True)
        except (subprocess.CalledProcessError, FileNotFoundError):
            self.log("Update cancelled by user or zenity is not installed.")
            self.button.set_sensitive(True)
            return

        # Get sudo password
        password_cmd = ["zenity", "--password", "--title=Sudo password required"]
        try:
            password_proc = subprocess.run(password_cmd, capture_output=True, text=True, check=True)
            password = password_proc.stdout.strip()
        except (subprocess.CalledProcessError, FileNotFoundError):
            self.log("Could not get sudo password.")
            self.button.set_sensitive(True)
            return

        if not password:
            self.log("No password entered. Aborting.")
            self.button.set_sensitive(True)
            return

        with tempfile.TemporaryDirectory() as tmpdir:
            self.log(f"Created temporary directory: {tmpdir}")

            mirrorlist_url = "https://iso.acreetionos.org:8448/Projects/Mirror_files/mirrorlist3"
            pacman_conf_url = "https://iso.acreetionos.org:8448/Projects/Mirror_files/pacman.conf"

            mirrorlist_path = os.path.join(tmpdir, "mirrorlist")
            pacman_conf_path = os.path.join(tmpdir, "pacman.conf")

            # Download files
            if not self.download_file("mirrorlist", mirrorlist_url, mirrorlist_path):
                self.button.set_sensitive(True)
                return
            
            if not self.download_file("pacman.conf", pacman_conf_url, pacman_conf_path):
                self.button.set_sensitive(True)
                return

            # Install files
            self.log("Installing files...")
            # Use two separate commands for sudo to avoid issues with long input strings
            install_mirrorlist_cmd = f"sudo -S install -Dm644 {mirrorlist_path} /etc/pacman.d/mirrorlist3"
            install_pacman_conf_cmd = f"sudo -S install -Dm644 {pacman_conf_path} /etc/pacman.conf"

            success = True
            try:
                self.run_sudo_command(install_mirrorlist_cmd, password)
                self.log("Successfully installed /etc/pacman.d/mirrorlist3")
            except subprocess.CalledProcessError as e:
                self.log_subprocess_error("Failed to install mirrorlist.", e)
                success = False

            if success:
                try:
                    self.run_sudo_command(install_pacman_conf_cmd, password)
                    self.log("Successfully installed /etc/pacman.conf")
                except subprocess.CalledProcessError as e:
                    self.log_subprocess_error("Failed to install pacman.conf.", e)
                    success = False
            
            if success:
                self.log("Update process completed successfully!")
                subprocess.run(["zenity", "--info", "--text=Mirrorlist and pacman.conf have been updated successfully."])
            else:
                self.log("Update process failed. See log for details.")
                subprocess.run(["zenity", "--error", "--text=Failed to install one or more files. See the application window for details."])

        self.button.set_sensitive(True)
        return False # Important for GLib.idle_add to remove the source

    def download_file(self, name, url, path):
        self.log(f"Downloading {name}...")
        try:
            subprocess.run(["curl", "-L", "-o", path, url], check=True, capture_output=True)
            self.log(f"{name.capitalize()} downloaded successfully.")
            return True
        except (subprocess.CalledProcessError, FileNotFoundError) as e:
            self.log(f"Failed to download {name}. Please check the URL and your internet connection.")
            if isinstance(e, subprocess.CalledProcessError):
                 self.log("Curl stderr: " + e.stderr.decode())
            return False

    def run_sudo_command(self, command, password):
        proc = subprocess.run(
            ["bash", "-c", command],
            input=password,
            capture_output=True,
            text=True,
            check=True
        )
        return proc

    def log_subprocess_error(self, message, e):
        self.log(message)
        self.log("Return code: " + str(e.returncode))
        if e.stdout:
            self.log("Stdout: " + e.stdout)
        if e.stderr:
            self.log("Stderr: " + e.stderr)


class MirrorUpdaterApp(Gtk.Application):
    def __init__(self):
        super().__init__(application_id='org.acreetionos.mirrorupdater')

    def do_activate(self):
        win = self.props.active_window
        if not win:
            win = MirrorUpdater(self)
        win.present()

if __name__ == "__main__":
    app = MirrorUpdaterApp()
    app.run([])
