#!/usr/bin/env python3
import os
import sys
import shutil
import subprocess

VERSION = "1.0.2"
CODENAME = "AMBROSO"
CONFIRM = "CONVERT_DEBIAN_TO_SENTINELOS"

def which(cmd):
    return shutil.which(cmd)

def backend_command(opts):
    cmd = ["sentinelos-convert-debian", "--run", "--mode", "desktop"]
    if opts.get("libreoffice"):
        cmd.append("--install-libreoffice")
    if opts.get("mate_apps"):
        cmd.append("--install-mate-apps")
    if opts.get("sentinel_suite"):
        cmd.append("--install-sentinel-suite")
    cmd += ["--appearance", opts.get("appearance", "sentinel-dark")]
    cmd += ["--confirm", CONFIRM]
    return cmd

def summary_text(opts=None):
    opts = opts or {
        "hardening": True,
        "branding": True,
        "aegis_public_branding": True,
        "sentinel_suite": False,
        "libreoffice": False,
        "mate_apps": False,
        "appearance": "sentinel-dark",
    }
    appearance = "SentinelOS Dark" if opts.get("appearance") == "sentinel-dark" else "SentinelOS Light"
    return "\n".join([
        f"SentinelOS Public Converter v1 — codename {CODENAME}",
        "",
        "Mode: Convert existing Debian desktop",
        "Clean install: Disabled / future ISO-only",
        "Private local repo: not bundled",
        "",
        "Core:",
        f"  SentinelOS hardening base: {'yes' if opts.get('hardening') else 'no'}",
        f"  SentinelOS branding/theme/icon baseline: {'yes' if opts.get('branding') else 'no'}",
        f"  Appearance: {appearance}",
        "",
        "AEGIS:",
        f"  Basic public AEGIS branding hooks: {'yes' if opts.get('aegis_public_branding') else 'no'}",
        "  Personal model artifacts: no",
        "  Personal path/vault files: no",
        "  AEGIS runtime auto-enable: no",
        "",
        "Optional applications:",
        f"  Sentinel Desktop Suite: {'yes' if opts.get('sentinel_suite') else 'no'}",
        f"  LibreOffice: {'yes' if opts.get('libreoffice') else 'no'}",
        f"  MATE desktop applications: {'yes' if opts.get('mate_apps') else 'no'}",
        "",
        "Safety:",
        "  No disk wipe in converter mode",
        "  No password/user/authentication changes",
        "  No private local repo bootstrap",
    ])

def can_gtk():
    try:
        import gi
        gi.require_version("Gtk", "3.0")
        from gi.repository import Gtk
        return True
    except Exception:
        return False

def launch_gtk():
    import gi
    gi.require_version("Gtk", "3.0")
    from gi.repository import Gtk, Gdk

    css = """
    window { background: #101418; color: #e7eef3; font-family: Sans; font-size: 10.5pt; }
    .root { background: #101418; color: #e7eef3; }
    .header { background: #0f141a; border-bottom: 1px solid #263541; padding: 18px; }
    .title { color: #e7eef3; font-size: 20pt; font-weight: 700; }
    .subtitle { color: #9aa7b2; font-size: 10.5pt; }
    .panel { background: #151b21; border: 1px solid #26333c; border-radius: 10px; padding: 14px; margin: 8px; }
    .section-title { color: #03C8FF; font-weight: 700; font-size: 12pt; }
    .help { color: #9aa7b2; font-size: 9.5pt; }
    checkbutton, radiobutton { color: #e7eef3; padding: 4px; }
    checkbutton:disabled, radiobutton:disabled { color: #6f7d87; }
    button { background: #1a2530; color: #e7eef3; border: 1px solid #2d4655; border-radius: 8px; padding: 8px 14px; }
    button:hover { background: #20313e; border-color: #03C8FF; }
    button.suggested-action { background: #123242; border-color: #03C8FF; color: #e7eef3; }
    textview, textview text { background: #0f1419; color: #e7eef3; border: 1px solid #26333c; }
    """
    provider = Gtk.CssProvider()
    provider.load_from_data(css.encode("utf-8"))
    Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

    class App(Gtk.Window):
        def __init__(self):
            super().__init__(title="SentinelOS Public Converter")
            self.set_default_size(840, 620)
            self.opts = {
                "hardening": True, "branding": True, "aegis_public_branding": True,
                "sentinel_suite": False, "libreoffice": False, "mate_apps": False,
                "appearance": "sentinel-dark",
            }
            outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
            outer.get_style_context().add_class("root")
            self.add(outer)
            header = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=4)
            header.get_style_context().add_class("header")
            outer.pack_start(header, False, False, 0)
            title = Gtk.Label(label="SentinelOS Public Converter")
            title.set_xalign(0); title.get_style_context().add_class("title")
            header.pack_start(title, False, False, 0)
            sub = Gtk.Label(label="v1 codename AMBROSO — public-safe Debian conversion frontend")
            sub.set_xalign(0); sub.get_style_context().add_class("subtitle")
            header.pack_start(sub, False, False, 0)
            body = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
            body.set_margin_left(12); body.set_margin_right(12); body.set_margin_top(10); body.set_margin_bottom(10)
            outer.pack_start(body, True, True, 0)
            body.pack_start(self.mode_panel(), False, False, 0)
            body.pack_start(self.core_panel(), False, False, 0)
            body.pack_start(self.aegis_panel(), False, False, 0)
            body.pack_start(self.optional_panel(), False, False, 0)
            body.pack_start(self.appearance_panel(), False, False, 0)
            body.pack_start(self.review_panel(), True, True, 0)
            footer = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
            footer.set_margin_left(12); footer.set_margin_right(12); footer.set_margin_bottom(10)
            outer.pack_start(footer, False, False, 0)
            pre = Gtk.Button(label="Run Preflight"); pre.connect("clicked", self.preflight); footer.pack_start(pre, False, False, 0)
            footer.pack_start(Gtk.Box(), True, True, 0)
            close = Gtk.Button(label="Close"); close.connect("clicked", lambda *_: Gtk.main_quit()); footer.pack_start(close, False, False, 0)
            apply = Gtk.Button(label="Begin Conversion"); apply.get_style_context().add_class("suggested-action"); apply.connect("clicked", self.apply); footer.pack_start(apply, False, False, 0)
            self.update_review()

        def section(self, title, help_text=None):
            p = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8)
            p.get_style_context().add_class("panel")
            lab = Gtk.Label(label=title); lab.set_xalign(0); lab.get_style_context().add_class("section-title")
            p.pack_start(lab, False, False, 0)
            if help_text:
                h = Gtk.Label(label=help_text); h.set_xalign(0); h.set_line_wrap(True); h.get_style_context().add_class("help")
                p.pack_start(h, False, False, 0)
            return p

        def mode_panel(self):
            p = self.section("Installation Mode", "Convert this Debian installation to SentinelOS. Clean install remains future ISO-only.")
            rb = Gtk.RadioButton.new_with_label_from_widget(None, "Convert this Debian installation to SentinelOS"); rb.set_active(True); p.pack_start(rb, False, False, 0)
            rb2 = Gtk.RadioButton.new_with_label_from_widget(rb, "Clean install SentinelOS — future ISO-only"); rb2.set_sensitive(False); p.pack_start(rb2, False, False, 0)
            return p

        def core_panel(self):
            p = self.section("Core System", "Safe foundational conversion controls.")
            self.hardening = Gtk.CheckButton(label="Apply SentinelOS hardening base"); self.hardening.set_active(True); self.hardening.connect("toggled", self.changed); p.pack_start(self.hardening, False, False, 0)
            self.branding = Gtk.CheckButton(label="Apply SentinelOS branding, theme, icon, tray, and login baseline"); self.branding.set_active(True); self.branding.connect("toggled", self.changed); p.pack_start(self.branding, False, False, 0)
            return p

        def aegis_panel(self):
            p = self.section("AEGIS", "Public-safe AEGIS branding hooks only. No personal model artifacts, vault paths, or runtime auto-enable.")
            self.aegis = Gtk.CheckButton(label="Include basic AEGIS branding hooks"); self.aegis.set_active(True); self.aegis.connect("toggled", self.changed); p.pack_start(self.aegis, False, False, 0)
            return p

        def optional_panel(self):
            p = self.section("Optional Applications", "Sentinel Desktop Suite is off by default and should only be selected when public packages/repositories are available.")
            self.suite = Gtk.CheckButton(label="Install Sentinel Desktop Suite if available"); self.suite.set_active(False); self.suite.connect("toggled", self.changed); p.pack_start(self.suite, False, False, 0)
            self.libre = Gtk.CheckButton(label="Install LibreOffice"); self.libre.set_active(False); self.libre.connect("toggled", self.changed); p.pack_start(self.libre, False, False, 0)
            self.mate = Gtk.CheckButton(label="Install MATE desktop applications"); self.mate.set_active(False); self.mate.connect("toggled", self.changed); p.pack_start(self.mate, False, False, 0)
            return p

        def appearance_panel(self):
            p = self.section("Appearance", "Public SentinelOS appearance.")
            self.dark = Gtk.RadioButton.new_with_label_from_widget(None, "SentinelOS Dark"); self.dark.set_active(True); self.dark.connect("toggled", self.changed); p.pack_start(self.dark, False, False, 0)
            self.light = Gtk.RadioButton.new_with_label_from_widget(self.dark, "SentinelOS Light"); self.light.connect("toggled", self.changed); p.pack_start(self.light, False, False, 0)
            return p

        def review_panel(self):
            p = self.section("Review")
            self.review = Gtk.TextView(); self.review.set_editable(False); self.review.set_cursor_visible(False); self.review.set_monospace(True)
            sw = Gtk.ScrolledWindow(); sw.set_min_content_height(210); sw.add(self.review)
            p.pack_start(sw, True, True, 0)
            return p

        def collect(self):
            self.opts["hardening"] = self.hardening.get_active()
            self.opts["branding"] = self.branding.get_active()
            self.opts["aegis_public_branding"] = self.aegis.get_active()
            self.opts["sentinel_suite"] = self.suite.get_active()
            self.opts["libreoffice"] = self.libre.get_active()
            self.opts["mate_apps"] = self.mate.get_active()
            self.opts["appearance"] = "sentinel-dark" if self.dark.get_active() else "sentinel-light"
            return dict(self.opts)

        def update_review(self):
            opts = self.collect()
            self.review.get_buffer().set_text(summary_text(opts) + "\n\nBackend command:\n  " + " ".join(backend_command(opts)))

        def changed(self, *_): self.update_review()

        def msg(self, title, body, typ=None):
            typ = typ or Gtk.MessageType.INFO
            d = Gtk.MessageDialog(self, 0, typ, Gtk.ButtonsType.OK, title)
            d.format_secondary_text(body); d.run(); d.destroy()

        def preflight(self, *_):
            if not which("sentinelos-public-converter"):
                self.msg("Preflight unavailable", "sentinelos-public-converter not installed.", Gtk.MessageType.ERROR); return
            p = subprocess.run(["sentinelos-public-converter", "--preflight"], text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            self.msg("Preflight result", p.stdout, Gtk.MessageType.INFO if p.returncode == 0 else Gtk.MessageType.ERROR)

        def apply(self, *_):
            opts = self.collect()
            runner = ["pkexec"] if which("pkexec") else (["sudo"] if which("sudo") else [])
            if not runner:
                self.msg("Privilege tool missing", "Neither pkexec nor sudo was found.", Gtk.MessageType.ERROR); return
            try:
                subprocess.Popen(runner + backend_command(opts))
                self.msg("Conversion launched", "The SentinelOS public conversion backend has been launched.")
            except Exception as e:
                self.msg("Launch failed", str(e), Gtk.MessageType.ERROR)

    win = App(); win.connect("destroy", Gtk.main_quit); win.show_all(); Gtk.main()
    return 0

def main():
    if "--summary" in sys.argv:
        print(f"SentinelOS Public Installer GUI\nversion: {VERSION}\ncodename: {CODENAME}\nprivate_repo: not bundled\npersonal_aegis_artifacts: excluded")
        return 0
    if "--verify" in sys.argv:
        ok = True
        if not which("python3"):
            print("missing command: python3"); ok = False
        print("gtk_frontend:", "available" if can_gtk() else "warning/not-available")
        print("cli_fallback: available")
        print("verify: ok" if ok else "verify: failed")
        return 0 if ok else 1
    if "--plan-example" in sys.argv:
        print(summary_text())
        print()
        print(" ".join(backend_command({"appearance":"sentinel-dark"})))
        return 0
    if os.environ.get("DISPLAY") and can_gtk():
        return launch_gtk()
    print(summary_text())
    print()
    print("GTK unavailable. Backend example:")
    print("  sudo " + " ".join(backend_command({"appearance":"sentinel-dark"})))
    return 0

if __name__ == "__main__":
    raise SystemExit(main())
