#!/usr/bin/python3


import logging
from typing import Any

from slpkg.config import config_load
from slpkg.load_data import LoadData
from slpkg.remove_packages import RemovePackages
from slpkg.repositories import Repositories
from slpkg.utilities import Utilities
from slpkg.views.display import View

logger = logging.getLogger(__name__)


class CleanSystem:  # pylint: disable=[R0902]
    """Detects packages not present in any enabled repository."""

    def __init__(self, options: dict[str, Any]) -> None:
        self.options = options
        self.repository = "all"  # Searching across all repositories

        self.cyan = config_load.cyan
        self.endc = config_load.endc
        self.red = config_load.red

        self.repos = Repositories()
        self.utils = Utilities()

        # Load data from all enabled repositories
        self.loader = LoadData()
        self.data = self.loader.load("*", message=not self.options.get("option_quiet"))

        # When loading all repositories ('*'), LoadData returns a nested dict: {repo_name: {pkg_name: data}}
        # We need to flatten it into a single set of package names.
        self.all_repo_packages: set[str] = set()
        for repo_data in self.data.values():
            self.all_repo_packages.update(repo_data.keys())

        self.view = View(self.options, self.repository, self.data)

    def _get_foreign_data(self, foreign_packages: list[str]) -> dict[str, dict[str, str]]:
        """Extract version and size info from local package logs for the view."""
        foreign_data: dict[str, dict[str, str]] = {}
        for full_name in foreign_packages:
            pkg_info = self.utils.split_package(full_name)
            name = pkg_info["name"]

            # Get size from local log file
            pkg_log = config_load.log_packages / full_name
            size = "0"
            if pkg_log.is_file():
                try:
                    # Look for 'UNCOMPRESSED PACKAGE SIZE' in the log
                    content = pkg_log.read_text(encoding="utf-8", errors="replace")
                    for line in content.splitlines():
                        if "UNCOMPRESSED PACKAGE SIZE:" in line:
                            size = line.split(":")[-1].strip().replace("K", "").strip()
                            break
                except OSError:
                    pass

            foreign_data[name] = {
                "version": pkg_info["version"],
                "arch": pkg_info["arch"],
                "build": pkg_info["build"],
                "tag": pkg_info["tag"],
                "size": size,
                "repository": "foreign"
            }
        return foreign_data

    def find_foreign_packages(self) -> list[str]:
        """Returns a list of installed packages not found in any enabled repository."""
        logger.info("Starting detection of foreign packages.")

        # Get all installed packages (full names)
        installed_packages = self.utils.all_installed().values()
        logger.debug("Total installed packages: %d", len(installed_packages))

        foreign_packages = []
        for full_name in installed_packages:
            # Extract the base name (e.g., 'ffmpeg' from 'ffmpeg-7.1-x86_64-1_SBo')
            name = self.utils.split_package(full_name)["name"]
            if name not in self.all_repo_packages:
                foreign_packages.append(full_name)

        logger.info("Detected %d foreign packages.", len(foreign_packages))
        return sorted(foreign_packages)

    def run(self) -> None:
        """Main execution logic for clean-system."""
        foreign_full_names = self.find_foreign_packages()

        if not foreign_full_names:
            if not self.options.get("option_quiet"):
                print(f"No foreign packages found. Your system is {self.cyan}clean{self.endc}.")
            return

        # Display the list
        foreign_names = [self.utils.split_package(fn)["name"] for fn in foreign_full_names]
        print(f"\n{self.cyan}Foreign packages found{self.endc} (not in any enabled repository):")
        for full_name in foreign_full_names:
            if self.options.get("option_quiet"):
                print(full_name)
            else:
                print(f"  - {full_name}")

        if self.options.get("option_quiet"):
            return

        count = len(foreign_full_names)
        noun = "package" if count == 1 else "packages"
        print(f"\nTotal: {self.cyan}{count}{self.endc} {noun}.")

        # Handle autoremove or prompt
        if self.options.get("option_autoremove"):
            print(f"\n{self.red}Autoremoving{self.endc} foreign packages...")

            # Create data structure for the view
            foreign_data = self._get_foreign_data(foreign_full_names)

            # RemovePackages expects (packages_names, options)
            remover = RemovePackages(foreign_names, self.options)

            # Inject foreign data into the remover's view
            remover.view.data.update(foreign_data)

            remover.remove()
        else:
            print("\nUse '--autoremove' to remove these packages from your system.")
