#!/usr/bin/python3


from __future__ import annotations

import logging
from typing import Any

from slpkg.choose_packages import Choose
from slpkg.config import config_load
from slpkg.load_data import LoadData
from slpkg.repositories import Repositories
from slpkg.sbo.slackbuild import Slackbuilds
from slpkg.utilities import Utilities
from slpkg.views.display import View

logger = logging.getLogger(__name__)


class Rebuild:  # pylint: disable=[R0902,R0903]
    """Rebuild all installed SlackBuilds packages from a repository."""

    def __init__(self, options: dict[str, Any], repository: str) -> None:
        self.options = options
        self.repository = repository
        self.repos = Repositories()
        self.utils = Utilities()
        self.load_data = LoadData()

        self._set_default_sbo_repository()

        self.choose = Choose(self.options, self.repository)
        self.data: dict[str, Any] = {}
        self.cyan = config_load.cyan
        self.endc = config_load.endc

    def _set_default_sbo_repository(self) -> None:
        """Set the default repository to 'sbo' or 'ponce' if none is selected."""
        if self.repository in {self.repos.slack_repo_name, ""}:
            if self.repos.repositories.get(self.repos.sbo_repo_name, {}).get("enable"):
                logger.info("Switching default repository from '%s' to '%s' for rebuild.",
                            self.repository, self.repos.sbo_repo_name)
                self.repository = self.repos.sbo_repo_name
            elif self.repos.repositories.get(self.repos.ponce_repo_name, {}).get("enable"):
                logger.info("Switching default repository from '%s' to '%s' for rebuild.",
                            self.repository, self.repos.ponce_repo_name)
                self.repository = self.repos.ponce_repo_name

    def _is_tag_match(self, pkg_tag: str, repo_tag: str) -> bool:
        """Check if the package tag matches the repository tag."""
        if repo_tag == "*":
            return True

        if not repo_tag:
            return False

        exact_match = pkg_tag == repo_tag
        with_underscore = f"_{pkg_tag}" == repo_tag
        stripped_repo = pkg_tag == repo_tag.lstrip("_")

        return exact_match or with_underscore or stripped_repo

    def run(self) -> None:
        """Main execution logic for rebuild."""
        logger.info("Executing 'rebuild' command (repo: %s).", self.repository)

        sbo_repos = {self.repos.sbo_repo_name, self.repos.ponce_repo_name}

        if self.repository not in sbo_repos:
            print(f"Error: 'rebuild' only supports SBo/Ponce repositories. "
                  f"Use 'reinstall' for binary repository '{self.repository}'.")
            return

        command = "rebuild"

        # 1. Load repository data
        self.data = self.load_data.load(self.repository, message=not self.options.get("option_quiet"))
        logger.debug("Loaded repository data for rebuild.")

        # 2. Get the repository tag
        repo_tag: str = (self.options.get("option_repo_tag")
                         or self.repos.repositories[self.repository].get("repo_tag", ""))

        logger.debug("Repository tag for '%s' is set to '%s' for filtering.", self.repository, repo_tag)

        # 3. Get all installed packages and filter by tag
        all_installed = self.utils.all_installed()
        rebuild_packages: list[str] = []

        for name, full_name in all_installed.items():
            pkg_info = self.utils.split_package(full_name)
            pkg_tag = pkg_info.get("tag", "")

            if self._is_tag_match(pkg_tag, repo_tag):
                if name in self.data:
                    rebuild_packages.append(name)
                    logger.debug("Added package '%s' (installed as '%s') for rebuild.", name, full_name)

        if not rebuild_packages:
            msg = f"No packages found to rebuild from repository '{self.repository}'"
            if repo_tag:
                msg += f" with tag '{repo_tag}'"
            print(f"{msg}.")
            logger.info(msg)
            return

        logger.info("Found %d packages for potential rebuild.", len(rebuild_packages))
        rebuild_packages = sorted(rebuild_packages)

        # 4. Handle selection if requested
        if self.options.get("option_select") or self.options.get("option_dialog"):
            logger.info("Prompting user for package selection for rebuild.")
            rebuild_packages = self.choose.packages(self.data, rebuild_packages, command, ordered=True)
            logger.debug("Packages after user selection for rebuild: %s", rebuild_packages)

        if not rebuild_packages:
            logger.info("No packages selected for rebuild. Exiting.")
            return

        # 5. Handle dry-run (check)
        if self.options.get("option_check"):
            logger.info("Dry-run requested for rebuild. Displaying packages.")
            self.options["option_reinstall"] = True
            view = View(self.options, self.repository, self.data)
            view.install_upgrade_packages(rebuild_packages, [], "reinstall")
            return

        # 6. Execute build/install process
        self.options["option_reinstall"] = True
        logger.info("Initiating SlackBuilds mass rebuild.")
        install_sbo = Slackbuilds(self.repository, self.data, rebuild_packages, self.options, mode="install")
        install_sbo.execute()

        logger.info("Rebuild command completed.")
