#!/usr/bin/python3


from __future__ import annotations

import logging
from typing import Any, cast

from slpkg.repositories import Repositories
from slpkg.utilities import Utilities

logger = logging.getLogger(__name__)


class Required:
    """Create a tuple of dependencies with the right order to install."""

    __slots__ = (
        "data",
        "full_requires",
        "name",
        "option_for_resolve_off",
        "repos",
        "utils",
    )

    def __init__(self, data: dict[str, dict[str, str]], name: str, options: dict[str, bool]) -> None:
        self.data = data
        self.name = name
        self.utils = Utilities()
        self.repos = Repositories()
        logger.debug("Initializing Required for package '%s'.", self.name)

        # Reads about how requires are listed, full listed is True
        # and normal listed is false.
        self.full_requires: bool = False
        if self.repos.repos_information.is_file():
            info = cast(dict[str, dict[str, Any]], self.utils.read_json_file(self.repos.repos_information))
            if name in data:
                repo_name: str = data[name]["repo"]
                if info.get(repo_name):
                    self.full_requires = info[repo_name].get("full_requires", False)
                    logger.debug(
                        "Read 'full_requires' flag as %s from repository information for '%s'.",
                        self.full_requires,
                        repo_name,
                    )
            else:
                logger.warning("Package '%s' not found in data during initialization.", name)

        self.option_for_resolve_off: bool = options.get("option_resolve_off", False)
        logger.debug("Option 'option_for_resolve_off' is set to %s.", self.option_for_resolve_off)

    def resolve(self) -> tuple[str, ...]:
        """Resolve the dependencies."""
        logger.info("Resolving dependencies for package '%s'.", self.name)
        dependencies: tuple[str, ...] = ()
        if not self.option_for_resolve_off:  # pylint: disable=[R1702]
            if self.name not in self.data:
                logger.error("Package '%s' not found in data. Cannot resolve dependencies.", self.name)
                return dependencies

            requires: list[str] = self.remove_deps(cast(list[str], self.data[self.name]["requires"]))
            logger.debug("Initial dependencies for '%s': %s", self.name, ", ".join(requires))

            # Resolve dependencies for some special repos.
            if not self.full_requires:
                logger.info("Performing full dependency resolution as 'full_requires' is False.")
                # for require in requires:
                i = 0
                while i < len(requires):
                    require = requires[i]
                    i += 1
                    if require not in self.data:
                        logger.warning(
                            "Dependency '%s' for package '%s' not found in data. Skipping resolution for it.",
                            require,
                            self.name,
                        )
                        continue

                    sub_requires: list[str] = self.remove_deps(cast(list[str], self.data[require]["requires"]))
                    logger.debug("Found sub-dependencies for '%s': %s", require, ", ".join(sub_requires))
                    for sub in sub_requires:
                        if sub not in requires and sub != self.name:
                            requires.append(sub)
                            logger.debug("Added transitive dependency '%s' to the list.", sub)
                        else:
                            if sub == self.name:
                                logger.warning(
                                    "Circular dependency detected: '%s' appears in its own dependency chain. Skipping.",
                                    self.name,
                                )
                            else:
                                logger.debug("Skipping sub-dependency '%s' (already in list).", sub)
            else:
                logger.info("Skipping full dependency resolution as 'full_requires' is True.")

            requires.reverse()
            dependencies = tuple(dict.fromkeys(requires))
            logger.info("Final resolved dependencies for '%s': %s", self.name, ", ".join(dependencies))

        return dependencies

    def remove_deps(self, requires: list[str]) -> list[str]:
        """Remove requirements that not in the repository.

        Args:
            requires (list[str]): List of requires.

        Returns:
            list: List of packages name.
        """
        filtered_requires: list[str] = []
        removed_deps: list[str] = []
        for req in requires:
            if req in self.data:
                filtered_requires.append(req)
            else:
                removed_deps.append(req)
        if removed_deps:
            logger.debug("Removed %d dependencies not in repository: %s", len(removed_deps), ", ".join(removed_deps))
        logger.debug("Filtered dependencies list size: %d", len(filtered_requires))
        return filtered_requires
