#!/usr/bin/python3


from __future__ import annotations

import logging

from slpkg.config import config_load
from slpkg.dialog_box import DialogBox
from slpkg.terminal_selector import TerminalSelector
from slpkg.upgrade import Upgrade
from slpkg.utilities import Utilities
from slpkg.views.process import ViewProcess

logger = logging.getLogger(__name__)


class ChooseDependencies:  # pylint: disable=[R0902,R0903]
    """
    Choose dependencies with dialog or with terminal selector.
    """

    def __init__(self, repository: str, data: dict[str, dict[str, str]], options: dict[str, bool], mode: str) -> None:
        logger.debug(
            "Initializing ChooseDependencies module for repository: '%s', mode: '%s', options: %s",
            repository,
            mode,
            options,
        )
        self.repository = repository
        self.data = data
        self.mode = mode

        self.dialog = config_load.dialog
        self.clear_screen = config_load.clear_screen

        self.upgrade = Upgrade(repository, data)
        self.utils = Utilities()
        self.dialogbox = DialogBox()

        self.option_for_reinstall: bool = options.get("option_reinstall", False)
        logger.debug(
            "ChooseDependencies initialized. Dialog enabled: %s, Reinstall option: %s",
            self.dialog,
            self.option_for_reinstall,
        )

    def choose(self, dependencies: list[str], view_process: ViewProcess) -> list[str]:
        """Choose dependencies for install with dialog tool or terminal selector.

        Args:
            dependencies (list[str]): List of dependency names.
            view_process (ViewProcess): An instance of ViewProcess for displaying progress.

        Returns:
            list[str]: List of selected dependency names.
        """
        logger.info("Starting dependency selection for %d dependencies in mode: '%s'.", len(dependencies), self.mode)
        if not dependencies:
            logger.info("No dependencies provided to choose from. Returning empty list.")
            return []

        title: str = " Choose dependencies you want to install "
        choices, initial_selection = self._build_choices(dependencies)

        view_process.done()
        logger.debug("View process done for dependency preparation.")

        return self._run_selector(choices, title, initial_selection)

    def _build_choices(
        self, dependencies: list[str]
    ) -> tuple[list[tuple[str, str, bool, str]], list[int]]:
        """Build the choices list and initial selection flags from dependencies.

        Args:
            dependencies (list[str]): Dependency package names.

        Returns:
            tuple: (choices, initial_selection) ready for the selector UI.
        """
        choices: list[tuple[str, str, bool, str]] = []
        initial_selection: list[int] = []

        for package in dependencies:
            logger.debug("Processing dependency '%s' for selection.", package)

            if package not in self.data:
                logger.warning("Dependency '%s' not found in repository data. Skipping from choices.", package)
                continue

            repo_ver: str = self.data[package]["version"]
            description: str = self.data[package]["description"]
            help_text: str = f"Description: {description}"
            installed: str = self.utils.is_package_installed(package)
            upgradeable: bool = self.upgrade.is_package_upgradeable(installed) if installed else False

            status: bool = not installed
            if self.mode == "upgrade" and upgradeable:
                status = True
                logger.debug("Dependency '%s' is upgradeable in upgrade mode. Status set to True.", package)
            if self.option_for_reinstall:
                status = True
                logger.debug("Reinstall option is active for '%s'. Status set to True.", package)

            if installed and not status:
                logger.debug("Dependency '%s' is installed. Status set to False.", package)

            initial_selection.append(int(status))
            choices.append((package, repo_ver, status, help_text))
            logger.debug(
                "Added choice for '%s': version '%s', status %s.", package, repo_ver, status
            )

        return choices, initial_selection

    def _run_selector(
        self,
        choices: list[tuple[str, str, bool, str]],
        title: str,
        initial_selection: list[int],
    ) -> list[str]:
        """Dispatch to dialog or terminal selector.

        Args:
            choices (list): Prepared choice tuples.
            title (str): UI window title.
            initial_selection (list[int]): Per-item pre-selection flags (terminal only).

        Returns:
            list[str]: Selected dependency names.
        """
        if self.dialog:
            logger.info("Using dialogbox for dependency selection.")
            return self._select_via_dialog(choices, title)
        logger.info("Using TerminalSelector for dependency selection.")
        return self._select_via_terminal(choices, title, initial_selection)

    def _select_via_dialog(
        self, choices: list[tuple[str, str, bool, str]], title: str
    ) -> list[str]:
        """Present dependency selection via dialog checklist.

        Args:
            choices (list): Choice tuples for the checklist.
            title (str): Dialog window title.

        Returns:
            list[str]: Selected dependency names (empty if cancelled).
        """
        height, width, list_height = 10, 70, 0
        text: str = f"There are {len(choices)} dependencies:"
        code, selected = self.dialogbox.checklist(text, title, height, width, list_height, choices)
        print(self.clear_screen, end="", flush=True)

        if code == "ok":
            logger.info("Dialogbox returned %d selected dependencies.", len(selected))
            return selected

        logger.info("Dialogbox selection cancelled or returned non-OK code ('%s'). Returning empty list.", code)
        return []

    def _select_via_terminal(
        self,
        choices: list[tuple[str, str, bool, str]],
        title: str,
        initial_selection: list[int],
    ) -> list[str]:
        """Present dependency selection via terminal selector.

        Args:
            choices (list): Choice tuples (names extracted from index 0).
            title (str): Selector window title.
            initial_selection (list[int]): Per-item pre-selection flags.

        Returns:
            list[str]: Selected dependency names.
        """
        is_upgrade: bool = self.mode == "upgrade"
        dependency_names = [choice[0] for choice in choices]
        selected = TerminalSelector(dependency_names, title, self.data, is_upgrade, initial_selection).select()
        logger.info("TerminalSelector returned %d selected dependencies.", len(selected))
        return selected
