#!/usr/bin/python3


from __future__ import annotations

import json
import logging
from pathlib import Path
from typing import cast

from slpkg.config import config_load
from slpkg.utilities import Utilities

logger = logging.getLogger(__name__)


class CheckBroken:  # pylint: disable=[R0902,R0903]
    """Check installed packages for missing tracked dependencies."""

    def __init__(self, options: dict[str, bool]) -> None:
        logger.debug("Initializing CheckBroken with options: %s", options)
        self.deps_log_file: Path = config_load.deps_log_file
        self.bold = config_load.bold
        self.grey = config_load.grey
        self.cyan = config_load.cyan
        self.red = config_load.red
        self.endc = config_load.endc
        self.option_quiet: bool = options.get("option_quiet", False)
        self.utils = Utilities()

    def _read_deps_log(self) -> dict[str, list[str]]:
        """Read deps.log and return the package → deps mapping."""
        if not self.deps_log_file.is_file():
            logger.info("deps.log not found: %s", self.deps_log_file)
            return {}
        try:
            data = json.loads(self.deps_log_file.read_text(encoding="utf-8"))
            if not isinstance(data, dict):
                logger.warning("deps.log is not a JSON object: %s", self.deps_log_file)
                return {}
            return cast(dict[str, list[str]], data)
        except (json.JSONDecodeError, OSError) as e:
            logger.warning("Failed to read deps.log '%s': %s", self.deps_log_file, e)
            return {}

    def run(self) -> None:
        """Scan deps.log and report packages with missing dependencies."""
        deps_log = self._read_deps_log()

        if not deps_log:
            if not self.option_quiet:
                print("No dependency log found. Install packages via slpkg to build the log.")
            return

        broken: dict[str, list[str]] = {}
        for pkg, deps in deps_log.items():
            missing = [dep for dep in deps if not self.utils.is_package_installed(dep)]
            if missing:
                broken[pkg] = missing

        if not broken:
            if not self.option_quiet:
                print("No broken dependencies found.")
            logger.info("No broken dependencies found.")
            return

        if self.option_quiet:
            for pkg in sorted(broken):
                print(pkg)
        else:
            print(f"{self.bold}Packages with missing dependencies:{self.endc}\n")
            for pkg in sorted(broken):
                installed = self.utils.is_package_installed(pkg)
                pkg_label = installed if installed else f"{self.grey}{pkg} (not installed){self.endc}"
                missing = broken[pkg]
                print(f"  {self.red}{pkg_label}{self.endc}")
                for dep in missing:
                    print(f"    {self.grey}missing:{self.endc} {dep}")
            count = len(broken)
            noun = "package" if count == 1 else "packages"
            print(f"\n{self.cyan}{count}{self.endc} {noun} with broken dependencies.")

        logger.info("check-broken completed. %d broken packages found.", len(broken))
