#!/usr/bin/env python3

import os
import sys
import subprocess
import importlib.util
import shutil

# 1. Sprache laden
from i18n import setup_language
setup_language('en')

import gi
gi.require_version("Gtk", "4.0")
gi.require_version("Gdk", "4.0")
from gi.repository import Gdk, Gio, GLib, Gtk

HERE = os.path.dirname(os.path.realpath(__file__))

def show_root_warning_and_exit():
    display = Gdk.Display.get_default()
    if display is not None:
        app = Gtk.Application(application_id="org.svi.rootcheck")
        def on_activate(app):
            temp_window = Gtk.Window(application=app)
            dialog = Gtk.MessageDialog(
                transient_for=temp_window,
                modal=True,
                message_type=Gtk.MessageType.ERROR,
                buttons=Gtk.ButtonsType.CLOSE,
                text=_("Root-Berechtigungen erforderlich"),
            )
            dialog.set_property("secondary-text", _("Bitte starte das Programm mit 'sudo'."))
            dialog.connect("response", lambda d, r: app.quit())
            dialog.present()
        app.connect("activate", on_activate)
        app.run([])
        sys.exit(1)

def _import_view(mod_basename: str, class_name: str):
    try:
        mod = importlib.import_module(mod_basename)
        return getattr(mod, class_name)
    except Exception as e:
        print(f"Fehler beim Import von {class_name}: {e}")
        sys.exit(1)

def check_root_privileges():
    if os.geteuid() != 0:
        show_root_warning_and_exit()

# Views importieren
WelcomeView = _import_view("welcome_view", "WelcomeView")
SystemConfigView = _import_view("system_config_view", "SystemConfigView")
UserConfigView = _import_view("user_config_view", "UserConfigView")
PartitioningView = _import_view("partitioning_view", "PartitioningView")
InstallModeView = _import_view("install_mode_view", "InstallModeView")
SoftwareConfigView = _import_view("software_config_view", "SoftwareConfigView")
SummaryView = _import_view("summary_view", "SummaryView")
InstallationView = _import_view("installation_view", "InstallationView")
CompletionView = _import_view("completion_view", "CompletionView")

class InstallerApp(Gtk.Application):
    def __init__(self):
        super().__init__(application_id="org.svi.App")
        self.window = None
        self.stack = None
        self.current_plan = {}
        self.available_languages = [
            ("Deutsch", "de"), ("English", "en"), ("Français", "fr"),
            ("Español", "es"), ("Italiano", "it"),
        ]

    def do_startup(self):
        Gtk.Application.do_startup(self)
        Gtk.Settings.get_default().set_property("gtk-application-prefer-dark-theme", True)

    def do_activate(self):
        if not self.window:
            self._load_css()
            self._build_ui()
            self._build_views()
        self.window.present()

    def _load_css(self):
        css_provider = Gtk.CssProvider()
        css_file = os.path.join(HERE, "ui.css")
        if os.path.exists(css_file):
            css_provider.load_from_path(css_file)
            Gtk.StyleContext.add_provider_for_display(Gdk.Display.get_default(), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

    def _build_ui(self):
        self.window = Gtk.ApplicationWindow(application=self)
        self.window.set_title("Simple Void Installer")
        self.window.set_default_size(1300, 1050)
        self.window.set_size_request(1150, 950)

        # 1. HeaderBar (NUR Titel und Sprache, KEINE Nav-Buttons)
        self.header_bar = Gtk.HeaderBar()
        self.window.set_titlebar(self.header_bar)

        lang_btn = Gtk.MenuButton()
        lang_btn.set_icon_name("preferences-desktop-locale-symbolic")
        popover = Gtk.Popover()
        menu_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        for name, code in self.available_languages:
            b = Gtk.Button(label=name)
            b.add_css_class("flat")
            b.connect("clicked", lambda x, c=code: self._reload_ui_with_language(c, popover))
            menu_box.append(b)
        popover.set_child(menu_box)
        lang_btn.set_popover(popover)
        self.header_bar.pack_end(lang_btn)

        # --- 2. Haupt-Layout (Vertical Box) ---
        # Diese Box enthält oben den Inhalt und unten die Buttons
        main_vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.window.set_child(main_vbox)

        # 3. Bereich für den Inhalt (ScrolledWindow)
        # set_vexpand(True) drückt alles unter sich (die Buttons) nach ganz unten
        self.root_scroll = Gtk.ScrolledWindow()
        self.root_scroll.set_vexpand(True)
        main_vbox.append(self.root_scroll)

        self.main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.main_box.set_halign(Gtk.Align.CENTER)
        self.main_box.set_margin_top(20)
        self.main_box.set_margin_bottom(20)
        self.main_box.set_margin_start(20)
        self.main_box.set_margin_end(20)
        self.root_scroll.set_child(self.main_box)

        self.stack = Gtk.Stack()
        self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
        self.stack.set_size_request(1100, -1)
        self.stack.connect("notify::visible-child-name", self._on_stack_changed)
        self.main_box.append(self.stack)

        # --- 4. Navigations-Leiste (Ganz unten) ---
        nav_area = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        nav_area.set_margin_start(30)
        nav_area.set_margin_end(30)
        nav_area.set_margin_top(15)
        nav_area.set_margin_bottom(20)
        main_vbox.append(nav_area)

        # Zurück-Button (Links unten)
        self.btn_back = Gtk.Button.new_with_label(_("Zurück"))
        self.btn_back.set_size_request(120, 45)
        self.btn_back.connect("clicked", self.on_back)
        nav_area.append(self.btn_back)

        # Ein Spacer, der den Platz in der Mitte füllt
        spacer = Gtk.Box()
        spacer.set_hexpand(True)
        nav_area.append(spacer)

        # Weiter-Button (Rechts unten)
        self.btn_next = Gtk.Button.new_with_label(_("Weiter"))
        self.btn_next.set_size_request(150, 45)
        self.btn_next.connect("clicked", self.on_next)
        self.btn_next.add_css_class("suggested-action")
        nav_area.append(self.btn_next)

    def _build_views(self):
        self.view_welcome = WelcomeView(self.on_next) 
        self.view_system_config = SystemConfigView()
        self.view_user_config = UserConfigView()
        self.view_part = PartitioningView()
        self.view_mode = InstallModeView(self.on_next)
        self.view_software = SoftwareConfigView()
        self.view_summary = SummaryView()
        self.view_install = InstallationView()
        self.view_done = CompletionView(self._on_restart_requested, self.quit)

        self.stack.add_named(self.view_welcome, "welcome")
        self.stack.add_named(self.view_system_config, "system_config")
        self.stack.add_named(self.view_user_config, "user_config")
        self.stack.add_named(self.view_part, "partition")
        self.stack.add_named(self.view_mode, "install_mode")
        self.stack.add_named(self.view_software, "software")
        self.stack.add_named(self.view_summary, "summary")
        self.stack.add_named(self.view_install, "install")
        self.stack.add_named(self.view_done, "done")

        self.view_install.set_completion_callback(self._on_installation_completed)
        self._update_nav_for("welcome")

    def _on_stack_changed(self, *args):
        name = self.stack.get_visible_child_name()
        if name:
            self._update_nav_for(name)

    def _update_nav_for(self, page: str):
        self.btn_back.set_visible(page not in ("welcome", "install", "done"))
        self.btn_next.set_visible(page != "done")
        self.btn_next.set_sensitive(page != "install")
        
        if page == "summary":
            self.btn_next.set_label(_("Installieren"))
        elif page == "install":
            self.btn_next.set_label(_("Warten..."))
        else:
            self.btn_next.set_label(_("Weiter"))

    def on_back(self, *args):
        order = ["welcome", "system_config", "user_config", "partition", "install_mode", "software", "summary"]
        current = self.stack.get_visible_child_name()
        if current in order:
            idx = order.index(current)
            if idx > 0:
                self.stack.set_visible_child_name(order[idx-1])

    def on_next(self, *args):
        page = self.stack.get_visible_child_name()
        try:
            if page == "welcome":
                self.stack.set_visible_child_name("system_config")
            elif page == "system_config":
                self.stack.set_visible_child_name("user_config")
            elif page == "user_config":
                self.view_user_config.validate_user_input()
                self.stack.set_visible_child_name("partition")
            elif page == "partition":
                self.view_part.validate_plan()
                self.stack.set_visible_child_name("install_mode")
            elif page == "install_mode":
                self.view_software.set_install_mode(self.view_mode.get_mode())
                self.stack.set_visible_child_name("software")
            elif page == "software":
                self._rebuild_summary()
                self.stack.set_visible_child_name("summary")
            elif page == "summary":
                self._confirm_install()
            elif page == "install":
                self.stack.set_visible_child_name("done")
        except ValueError as e:
            self._show_warning(str(e))

    def _rebuild_summary(self):
        try:
            plan = self._collect_plan()
            self.current_plan = plan
            device = plan.get("device") or _("Kein Laufwerk gewählt")
            
            # 1. Namen der Partitionierungs-Modi übersetzen
            mode_map = {
                "erase": _("Ganze Festplatte löschen"),
                "free": _("Freien Speicherplatz verwenden"),
                "existing": _("Vorhandene Partition")
            }
            mode_display = mode_map.get(plan.get("mode"), plan.get("mode"))
            
            # Falls "Freier Platz" gewählt wurde, die reservierte GB-Größe anhängen
            if plan.get("mode") == "free" and "free_space" in plan:
                mode_display += f" ({plan['free_space']['root_size_gib']} GiB)"

            # 2. Dateisystem und Snapshot-Info vorbereiten
            fs = plan.get("auto_layout", {}).get("filesystem", "ext4")

            # 3. Das Datenpaket für die Anzeige zusammenstellen
            summary_data = {
                _("Sprache"): plan.get("language"),
                _("Tastatur"): plan.get("keyboard"),
                _("Ziel-Laufwerk"): plan.get("device"),
                _("Modus"): mode_display,
                _("Dateisystem"): fs.upper(),
                _("Benutzer"): plan.get("user", {}).get("name"),
                _("Software"): f"{len(plan.get('software', []))} Pakete",
                _("Install-Art"): _("Live-Klon") if plan.get("install_source") == "live" else _("Netinstall")
            }
            
            # 4. UI aktualisieren
            self.view_summary.update_summary_data(summary_data)
            
        except Exception as e:
            # Falls etwas schief geht, zeigen wir eine Warnung statt eines Absturzes
            self._show_warning(f"Fehler bei der Zusammenfassung: {e}")

    def _collect_plan(self) -> dict:
        plan = self.view_part.get_plan()
        chosen_fs = plan.get("auto_layout", {}).get("filesystem", "ext4")
        plan.update({
            "language": self.view_system_config.get_selected_language(),
            "timezone": self.view_system_config.get_selected_timezone(),
            "keyboard": self.view_system_config.get_selected_keyboard_layout(),
            "install_source": self.view_mode.get_mode(),
            "mirror_url": self.view_software.get_mirror_url(),
            "software": self.view_software.get_selected_packages(chosen_fs),
            "copy_option": self.view_software.get_copy_option(),
            "user": self.view_user_config.get_user_payload(),
        })
        return plan

    def _confirm_install(self):
        dlg = Gtk.MessageDialog(transient_for=self.window, modal=True, message_type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.YES_NO, text=_("Installation starten?"))
        dlg.set_property("secondary-text", _("Alle Daten auf dem Ziel-Laufwerk gehen verloren!"))
        def on_res(d, r):
            d.destroy()
            if r == Gtk.ResponseType.YES:
                self.view_install.set_plan(self.current_plan)
                self.stack.set_visible_child_name("install")
                GLib.idle_add(self.view_install.start_installation)
        dlg.connect("response", on_res)
        dlg.present()

    def _on_installation_completed(self, success: bool):
        if success:
            self.btn_next.set_sensitive(True)
            self.btn_next.set_label(_("Abschließen"))
        else:
            self._show_warning(_("Fehler während der Installation."))

    def _on_restart_requested(self, *args):
        subprocess.run(["reboot"])

    def _reload_ui_with_language(self, code, popover):
        popover.popdown()
        setup_language(code)
        # UI neu aufbauen
        pages = ["welcome", "system_config", "user_config", "partition", "install_mode", "software", "summary", "install", "done"]
        for name in pages:
            child = self.stack.get_child_by_name(name)
            if child: self.stack.remove(child)
        
        self._build_views()
        self.stack.set_visible_child_name("welcome")
        self.btn_back.set_label(_("Zurück"))
        self.btn_next.set_label(_("Weiter"))

    def _show_warning(self, text: str):
        dlg = Gtk.MessageDialog(transient_for=self.window, modal=True, message_type=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.OK, text=_("Hinweis"), secondary_text=text)
        dlg.connect("response", lambda d, r: d.destroy())
        dlg.present()

if __name__ == "__main__":
    check_root_privileges()
    app = InstallerApp()
    app.run(sys.argv)
