#!/usr/bin/python3


from __future__ import annotations

import json
import logging
from pathlib import Path
from typing import Any, Optional

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

logger = logging.getLogger(__name__)


class Mark:  # pylint: disable=[R0902,R0903]
    """Mark packages as manually installed to exclude them from orphans."""

    def __init__(self, packages: list[str], options: Optional[dict[str, Any]] = None) -> None:
        self.packages = packages
        self.marks_log_file: Path = config_load.marks_log_file
        self.bold = config_load.bold
        self.grey = config_load.grey
        self.cyan = config_load.cyan
        self.green = config_load.green
        self.endc = config_load.endc
        self.unmark: bool = (options or {}).get("option_unmark", False)
        self.quiet: bool = (options or {}).get("option_quiet", False)
        self.utils = Utilities()

    def _read_marks_log(self) -> set[str]:
        """Read marks.log, returning an empty set if missing or invalid."""
        if not self.marks_log_file.is_file():
            logger.info("marks.log not found: %s", self.marks_log_file)
            return set()
        try:
            data = json.loads(self.marks_log_file.read_text(encoding="utf-8"))
            if not isinstance(data, list):
                logger.warning("marks.log is not a JSON array: %s", self.marks_log_file)
                return set()
            return {str(p) for p in data}
        except (json.JSONDecodeError, OSError) as e:
            logger.warning("Failed to read marks.log '%s': %s", self.marks_log_file, e)
            return set()

    def _write_marks_log(self, marks: set[str]) -> None:
        """Write sorted list of marks to marks.log."""
        try:
            self.marks_log_file.write_text(
                json.dumps(sorted(marks), indent=2) + "\n",
                encoding="utf-8",
            )
            logger.info("marks.log written: %d entries.", len(marks))
        except OSError as e:
            logger.error("Failed to write marks.log '%s': %s", self.marks_log_file, e)

    def view(self) -> None:
        """List marked packages, or mark/unmark based on self.packages."""
        if self.unmark and not self.packages:
            self._unmark_all()
        elif not self.packages:
            self._list()
        elif self.unmark:
            self._unmark()
        else:
            self._mark()

    def _list(self) -> None:
        """Display all manually marked packages."""
        marks = sorted(self._read_marks_log())
        if self.quiet:
            for name in marks:
                print(name)
            return
        print(f"{self.bold}Manually marked packages:{self.endc}")
        if not marks:
            print(" No manually marked packages found.")
            return
        for name in marks:
            print(f"  {self.green}{name}{self.endc}")
        count = len(marks)
        noun = "package" if count == 1 else "packages"
        print(f"\nFound {self.cyan}{count}{self.endc} manually marked {noun}.")
        print(f"Run '{self.bold}slpkg mark <package> --unmark{self.endc}' to unmark.")
        logger.info("Mark list view completed. %d marks displayed.", count)

    def _mark(self) -> None:
        """Mark packages as manually installed."""
        marks = self._read_marks_log()
        marks.update(self.packages)
        self._write_marks_log(marks)
        print(f"{self.bold}Marked as manually installed:{self.endc}")
        for name in sorted(self.packages):
            print(f"  {self.green}{name}{self.endc}")
        logger.info("Marked as manually installed: %s", ", ".join(self.packages))

    def _unmark(self) -> None:
        """Unmark packages (treat as auto-installed again)."""
        marks = self._read_marks_log()
        for name in self.packages:
            marks.discard(name)
        self._write_marks_log(marks)
        print(f"{self.bold}Unmarked (auto-installed):{self.endc}")
        for name in self.packages:
            print(f"  {self.grey}{name}{self.endc}")
        logger.info("Unmarked (auto-installed): %s", ", ".join(self.packages))

    def _unmark_all(self) -> None:
        """Remove all marks."""
        marks = self._read_marks_log()
        if not marks:
            print(" No manually marked packages found.")
            return
        self._write_marks_log(set())
        print(f"{self.bold}Unmarked all packages (auto-installed):{self.endc}")
        for name in sorted(marks):
            print(f"  {self.grey}{name}{self.endc}")
        logger.info("Unmarked all %d packages.", len(marks))
