#!/usr/bin/env python3
"""Edubuntu 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,
    GSCHEMA_CONTENTS,
    GSCHEMA_OVERRIDES,
    SETUP_CHOICES,
    TERTIARY_LABEL,
    apply_default,
    apply_user_default,
    autoremove_packages,
    build_package_table,
    get_current_default,
    query_user_defaults,
    install_packages,
    is_gnome_session,
    list_non_admin_users,
    update_apt_cache,
)
from ui.base import InstallerUI, 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), LXQt (Lubuntu)
    GTK desktops: GNOME (Ubuntu, Edubuntu), 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() -> InstallerUI:
    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 _build_setup_items(current: str) -> list[ChecklistItem]:
    return [
        ChecklistItem(
            key=label,
            label=_(label),
            description="",
            checked=(current == label),
        )
        for label in SETUP_CHOICES
    ]


def _main_loop(ui: InstallerUI) -> None:

    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
        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

        pkg_items = [
            ChecklistItem(
                key=pkg.name,
                label=pkg.name,
                description=pkg.description,
                checked=pkg.installed,
            )
            for pkg in pkg_table
        ]

        gnome = is_gnome_session()

        if gnome:
            # Gather data for the Default Setup tab
            global_default = get_current_default()
            global_setup_items = _build_setup_items(global_default)

            usernames = list_non_admin_users()
            user_defaults = query_user_defaults(usernames)

            def _user_default_fn(uname: str) -> str:
                return user_defaults.get(uname, TERTIARY_LABEL)

            result = ui.show_installer_tabs(
                APP_TITLE,
                _("Select or deselect metapackage(s) to modify "
                  "installation status."),
                pkg_items,
                _("Default setup for all users"),
                global_setup_items,
                _("Override for a specific user"),
                usernames,
                _user_default_fn,
                ok_label=_("Apply"),
                cancel_label=_("Close"),
                width=950,
                height=600,
            )

            if result is None:
                return

            selected_set, g_choice, sel_user, u_choice = (
                set(result[0]),
                result[1],
                result[2],
                result[3],
            )

            # Apply global default if changed
            if g_choice and g_choice != global_default:
                ui.show_progress(
                    APP_TITLE,
                    _("Applying global default setup…"),
                    lambda _out, _prog: apply_default(g_choice),
                )

            # Apply per-user default if changed
            if (
                sel_user
                and u_choice
                and u_choice != user_defaults.get(sel_user, TERTIARY_LABEL)
            ):
                ui.show_progress(
                    APP_TITLE,
                    _("Applying per-user default setup…"),
                    lambda _out, _prog: apply_user_default(sel_user, u_choice),
                )
        else:
            selected = ui.show_checklist(
                APP_TITLE,
                _("Select or deselect metapackage(s) to modify "
                  "installation status."),
                pkg_items,
                ok_label=_("Modify Installed Package Selection"),
                cancel_label=_("Close"),
                width=950,
                height=600,
            )
            if selected is None:
                return
            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}

        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."),
                    )

        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.\n\n"
                "If you are uninstalling more than one metapackage, you "
                "will be asked for your password more than once."
            ).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()
