#!/usr/bin/env python3
"""Ubuntu Studio Installer."""

from __future__ import annotations

import os
import sys
import textwrap
from pathlib import Path

_pkg_dir = Path(__file__).resolve().parent
if str(_pkg_dir) not in sys.path:
    sys.path.insert(0, str(_pkg_dir))

from backend import (  # noqa: E402
    APP_TITLE,
    autoremove_packages,
    build_package_table,
    install_packages,
    run_installer_fix,
    update_apt_cache,
)
from ui.base import AudioConfigUI, ChecklistItem  # noqa: E402
from i18n import _  # noqa: E402


# ======================================================================


def _detect_toolkit() -> str:
    """Return 'qt' or 'gtk' based on the running desktop.

    Qt desktops:  KDE Plasma (Kubuntu, Ubuntu Studio), LXQt (Lubuntu)
    GTK desktops: GNOME (Ubuntu), Xfce (Xubuntu), MATE (Ubuntu MATE),
                  Budgie (Ubuntu Budgie), Cinnamon (Ubuntu Cinnamon),
                  Unity (Ubuntu Unity)
    """
    desktop = os.environ.get("XDG_CURRENT_DESKTOP", "").lower()
    session = os.environ.get("DESKTOP_SESSION", "").lower()
    if any(tok in desktop for tok in ("kde", "plasma", "lxqt")):
        return "qt"
    if "plasma" in session or "lxqt" in session:
        return "qt"
    return "gtk"


def _create_ui() -> AudioConfigUI:
    """Pick the right UI backend, with fallback."""
    preferred = _detect_toolkit()
    if preferred == "qt":
        try:
            from ui.qt_ui import QtUI
            ui = QtUI()
            ui.init()
            return ui
        except ImportError:
            pass  # fall through to GTK
    try:
        from ui.gtk_ui import GtkUI
        ui = GtkUI()
        ui.init()
        return ui
    except ImportError:
        pass
    # Last resort: try Qt even on non-KDE desktops
    try:
        from ui.qt_ui import QtUI
        ui = QtUI()
        ui.init()
        return ui
    except ImportError:
        print(
            _("ERROR: Neither GTK 4 (python3-gi + gir1.2-adw-1) nor "
              "PyQt6 (python3-pyqt6) is available."),
            file=sys.stderr,
        )
        sys.exit(1)


# ======================================================================


def _main_loop(ui: AudioConfigUI) -> None:
    """Run the main installer loop."""

    while True:
        # Refresh apt cache
        ui.show_progress(
            APP_TITLE,
            _("Updating package cache…"),
            lambda out, _prog: update_apt_cache(on_output=out),
        )

        # Build the package table (with a progress indication)
        table = [None]

        def _build():
            table[0] = build_package_table()

        ui.show_progress(
            APP_TITLE,
            _("Building Package Table…"),
            lambda _out, _prog: _build(),
        )
        pkg_table = table[0]
        if pkg_table is None:
            ui.show_error(APP_TITLE, _("Failed to build the package table."))
            return

        # Build checklist items
        items = [
            ChecklistItem(
                key=pkg.name,
                label=pkg.name,
                description=pkg.description,
                checked=pkg.installed,
            )
            for pkg in pkg_table
        ]

        selected = ui.show_checklist(
            APP_TITLE,
            _("Select or deselect package(s) to modify installation status."),
            items,
            ok_label=_("Modify Installed Package Selection"),
            cancel_label=_("Close"),
            width=950,
            height=600,
        )

        if selected is None:
            return  # user closed

        selected_set = set(selected)
        all_names = {pkg.name for pkg in pkg_table}
        installed_names = {pkg.name for pkg in pkg_table if pkg.installed}

        # --- Packages to install (selected but not installed) ---
        to_install = sorted(selected_set - installed_names)

        if to_install:
            install_msg = _("The following packages will be installed by this "
                            "action:\n\n{packages}\n\n"
                            "You may be asked for your password more than once.\n"
                            "Do you wish to continue?").format(
                                packages="\n".join(to_install))

            if ui.show_question(
                APP_TITLE,
                install_msg,
                ok_label=_("Continue"),
                cancel_label=_("Skip/Go Back"),
            ):
                install_result = [False]

                def _do_install(on_output, on_progress):
                    install_result[0] = install_packages(
                        to_install, on_output=on_output, on_progress=on_progress,
                    )

                ui.show_progress(
                    APP_TITLE,
                    _("Installing packages…"),
                    _do_install,
                )

                if not install_result[0]:
                    ui.show_error(
                        APP_TITLE,
                        _("Package installation failed."),
                    )

                # If ubuntustudio-audio was just installed, run the fix
                if "ubuntustudio-audio" in to_install:
                    run_installer_fix()
                    ui.show_warning(
                        APP_TITLE,
                        _("Please log out and log in for proper audio "
                          "configuration to take effect."),
                    )

        # --- Packages to remove (installed but not selected) ---
        to_remove = sorted(installed_names - selected_set)

        if to_remove:
            # Gather dependencies that may also be removed
            from backend import apt_cache_depends
            all_deps: list[str] = []
            for pkg in to_remove:
                all_deps.extend(apt_cache_depends(pkg))
            # De-duplicate and format
            dep_list = sorted(set(all_deps))
            dep_text = textwrap.fill(" ".join(dep_list), width=80)

            remove_msg = _(
                "The following packages may be removed by this action:\n\n"
                "{dep_list}\n\n"
                "If you do not wish to have any one of these individual "
                "packages removed, simply reinstall them. No settings are "
                "being removed by uninstallation. Additionally, some of "
                "these packages may be required by other packages and may "
                "not be uninstalled, so parts of this list may not apply "
                "to you."
            ).format(dep_list=dep_text)

            if ui.show_question(
                APP_TITLE,
                remove_msg,
                ok_label=_("Continue"),
                cancel_label=_("Skip/Go Back"),
            ):
                ui.show_progress(
                    APP_TITLE,
                    _("Removing packages…"),
                    lambda out, prog: autoremove_packages(
                        to_remove, on_output=out, on_progress=prog,
                    ),
                )


# ======================================================================


def main() -> None:
    ui = _create_ui()
    _main_loop(ui)
    ui.quit()


if __name__ == "__main__":
    main()
