#!/usr/bin/env python3
from __future__ import annotations

import shlex
import shutil
import subprocess
from pathlib import Path
import tkinter as tk
from tkinter import messagebox

APP_NAME = "Minimal Casper"
APP_VERSION = "0.1.0"
COPYRIGHT_TEXT = "© 2026 Lorenzo DM Dev BoostMedia per Ufficio Zero — Licenza GPL3"

BASE_DIR = Path(__file__).resolve().parent
SCRIPTS_DIR = BASE_DIR / "scripts"

# Numero di colonne della griglia dei pulsanti
GRID_COLUMNS = 2

SCRIPT_DEFINITIONS: list[dict[str, str]] = [
    {
        "label": "FASE 1 - Verifica dei pacchetti",
        "filename": "script_1.sh",
        "description": "Fase 1 di aggiornamento di sistema",
    },
    {
        "label": "FASE 2 - Aggiorna la tua Minimal",
        "filename": "script_2.sh",
        "description": "Fase 2 di aggiornamento di sistema",
    },
    {
        "label": "FASE 3 - Installa i pacchetti necessari",
        "filename": "script_3.sh",
        "description": "Fase 3 di aggiornamento di sistema",
    },
    {
        "label": "FASE 4 - Prepara le sources",
        "filename": "script_4.sh",
        "description": "Preparazione delle sorgenti software",
    },
    {
        "label": "FASE 5 - Prepara Nala",
        "filename": "script_5.sh",
        "description": "Preparazione di Nala",
    },
    {
        "label": "FASE 6 - Termina i processi non necessari",
        "filename": "script_6.sh",
        "description": "Chiusura dei processi non necessari",
    },
    {
        "label": "FASE 7 - Esegui l'upgrade con Nala",
        "filename": "script_7.sh",
        "description": "Upgrade finale del sistema tramite Nala",
    },
    {
        "label": "FASE 8 - Riavvia",
        "filename": "script_8.sh",
        "description": "Upgrade finale del sistema tramite Nala",
    },
]


class MinimalCasperApp:
    def __init__(self, root: tk.Tk) -> None:
        self.root = root
        self.root.title(f"{APP_NAME} {APP_VERSION}")
        self.root.minsize(760, 520)
        self.root.configure(padx=18, pady=18)

        self.status_var = tk.StringVar(value="Pronti ad eseguire l'upgrade")

        self._build_ui()

    def _build_ui(self) -> None:
        title = tk.Label(
            self.root,
            text=APP_NAME,
            font=("TkDefaultFont", 16, "bold"),
            anchor="center",
        )
        title.pack(fill="x", pady=(0, 8))

        subtitle = tk.Label(
            self.root,
            text=(
                "Launcher Grafico per Aggiornamento UZL Minimal\n\n"
                "Il team di Ufficio Zero consiglia sempre una installazione ex novo del sistema e mai un upgrade per questioni di sicurezza.\n"
                "Le operazioni potrebbero durare a lungo (dipende dal vostro hardware), per cui una volta iniziate dovranno essere completate.\n"
                "Effettuate prima il backup dei vostri dati."
            ),
            anchor="center",
            justify="center",
            wraplength=720,
        )
        subtitle.pack(fill="x", pady=(0, 18))

        grid_frame = tk.Frame(self.root)
        grid_frame.pack(fill="both", expand=True)

        for col in range(GRID_COLUMNS):
            grid_frame.grid_columnconfigure(col, weight=1, uniform="buttons")

        for index, definition in enumerate(SCRIPT_DEFINITIONS):
            row = index // GRID_COLUMNS
            col = index % GRID_COLUMNS
            self._add_script_card(grid_frame, definition, row, col)

        bottom_frame = tk.Frame(self.root)
        bottom_frame.pack(fill="x", pady=(18, 0))

        status_label = tk.Label(
            bottom_frame,
            textvariable=self.status_var,
            anchor="w",
        )
        status_label.pack(fill="x")

        footer = tk.Label(
            bottom_frame,
            text=COPYRIGHT_TEXT,
            anchor="center",
            justify="center",
        )
        footer.pack(fill="x", pady=(10, 0))

    def _add_script_card(
        self,
        parent: tk.Widget,
        definition: dict[str, str],
        row: int,
        col: int,
    ) -> None:
        card = tk.LabelFrame(
            parent,
            text=definition["label"],
            padx=10,
            pady=10,
        )
        card.grid(row=row, column=col, padx=8, pady=8, sticky="nsew")

        description = tk.Label(
            card,
            text=definition["description"],
            anchor="w",
            justify="left",
            wraplength=300,
        )
        description.pack(fill="x", pady=(0, 10))

        button = tk.Button(
            card,
            text="Avvia",
            command=lambda d=definition: self.launch_script(d),
        )
        button.pack(fill="x")

    def launch_script(self, definition: dict[str, str]) -> None:
        script_path = SCRIPTS_DIR / definition["filename"]

        if not script_path.exists():
            messagebox.showerror(
                APP_NAME,
                f"Script non trovato:\n{script_path}",
            )
            self.status_var.set(f"Errore: manca {script_path.name}")
            return

        try:
            terminal_command = self._resolve_terminal_command(script_path)
            subprocess.Popen(terminal_command)
            self.status_var.set(f"Avviato {script_path.name}")
        except FileNotFoundError:
            messagebox.showerror(
                APP_NAME,
                "Nessun terminale compatibile trovato sul sistema.\n"
                "Installa o configura un emulatore di terminale supportato.",
            )
            self.status_var.set("Errore: terminale non trovato")
        except Exception as exc:
            messagebox.showerror(
                APP_NAME,
                f"Impossibile avviare il terminale:\n{exc}",
            )
            self.status_var.set("Errore durante l'avvio del terminale")

    def _resolve_terminal_command(self, script_path: Path) -> list[str]:
        working_dir = str(script_path.parent)
        shell_cmd = self._build_shell_command(script_path)

        candidates: list[list[str]] = [
            ["xdg-terminal-exec", "--", "bash", "-lc", shell_cmd],
            ["x-terminal-emulator", "-e", "bash", "-lc", shell_cmd],
            ["gnome-terminal", "--", "bash", "-lc", shell_cmd],
            ["konsole", "--workdir", working_dir, "-e", "bash", "-lc", shell_cmd],
            ["xfce4-terminal", "--working-directory", working_dir, "-x", "bash", "-lc", shell_cmd],
            ["mate-terminal", "--working-directory", working_dir, "-x", "bash", "-lc", shell_cmd],
            ["lxterminal", "-e", f"bash -lc {shlex.quote(shell_cmd)}"],
            ["xterm", "-T", APP_NAME, "-e", "bash", "-lc", shell_cmd],
        ]

        for candidate in candidates:
            if shutil.which(candidate[0]):
                return candidate

        raise FileNotFoundError("Nessun terminale supportato disponibile")

    @staticmethod
    def _build_shell_command(script_path: Path) -> str:
        quoted_dir = shlex.quote(str(script_path.parent))
        quoted_script = shlex.quote(str(script_path))

        return (
            f"cd {quoted_dir} && "
            f"bash {quoted_script}; "
            "status=$?; "
            'echo; '
            'echo "----------------------------------------"; '
            'echo "Esecuzione terminata con codice: ${status}"; '
            'echo "Premi INVIO per chiudere il terminale"; '
            'read -r; '
            'exit ${status}'
        )


def main() -> int:
    root = tk.Tk()
    MinimalCasperApp(root)
    root.mainloop()
    return 0


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