#!/usr/bin/python3


import json
import logging
import shutil
from typing import Any

from slpkg.config import config_load
from slpkg.utilities import Utilities
from slpkg.views.process import ViewProcess

logger = logging.getLogger(__name__)


class Stats:  # pylint: disable=[R0902,R0903]
    """Collects and displays installation statistics."""

    def __init__(self, options: dict[str, Any]) -> None:
        self.options = options
        self.utils = Utilities()
        self.view_process = ViewProcess()

        self.cyan = config_load.cyan
        self.green = config_load.green
        self.yellow = config_load.yellow
        self.red = config_load.red
        self.endc = config_load.endc
        self.bold = config_load.bold
        self.columns, _ = shutil.get_terminal_size()

    def _get_stats(self) -> dict[str, Any]:
        """Gather statistics about installed packages."""
        logger.info("Gathering system statistics.")
        installed = self.utils.all_installed()

        repo_stats: dict[str, dict[str, Any]] = {}
        all_pkgs_info = []
        total_size = 0

        for pkg_name, full_name in installed.items():
            parsed = self.utils.split_package(full_name)
            tag = parsed.get("tag", "slack").lower()
            if not tag:
                tag = "slack"

            if tag not in repo_stats:
                repo_stats[tag] = {"count": 0, "size": 0}

            repo_stats[tag]["count"] += 1

            # Read installed size from the log file header (fast: one line parse).
            pkg_size = self.utils.package_log_size(full_name)
            repo_stats[tag]["size"] += pkg_size
            total_size += pkg_size

            all_pkgs_info.append({
                "name": pkg_name,
                "full_name": full_name,
                "size": pkg_size,
                "tag": tag
            })

        return {
            "repositories": repo_stats,
            "packages": all_pkgs_info,
            "total_count": len(installed),
            "total_size": total_size
        }

    def _display_top_packages(self, packages: list[dict[str, Any]], limit: int) -> None:
        """Display the largest installed packages."""
        print(f"\n{self.bold}Top {limit} Largest Packages{self.endc}")
        print("-" * (self.columns - 1))

        sorted_pkgs = sorted(packages, key=lambda x: x["size"], reverse=True)

        for i, pkg in enumerate(sorted_pkgs[:limit], 1):
            size_str = self.utils.convert_file_sizes(pkg["size"])
            print(f"{i:>3}. {pkg['name']:<30} | {size_str:>10} ({pkg['tag']})")

    def _display_packages_per_repo(self, repos: dict[str, dict[str, Any]], total_count: int) -> None:
        """Display package count bar chart sorted by count descending."""
        print(f"\n{self.bold}Packages per repository{self.endc}")
        print("-" * (self.columns - 1))

        sorted_tags = sorted(repos.items(), key=lambda x: x[1]["count"], reverse=True)

        for tag, r_data in sorted_tags:
            count = r_data["count"]
            size_str = self.utils.convert_file_sizes(r_data["size"])
            percent = (count / total_count) * 100
            bar_len = int((percent / 100) * 30)
            ascii_bar = f"{self.green}{'#' * bar_len}{self.endc}{' ' * (30 - bar_len)}"
            print(f"{tag:<12} [{ascii_bar}] {count:>5} pkgs ({percent:>5.1f}%) | {size_str:>10}")

    def _display_disk_usage_per_repo(self, repos: dict[str, dict[str, Any]], total_size: int) -> None:
        """Display disk usage bar chart sorted by size descending."""
        print(f"\n{self.bold}Disk usage per repository{self.endc}")
        print("-" * (self.columns - 1))

        sorted_tags = sorted(repos.items(), key=lambda x: x[1]["size"], reverse=True)

        for tag, r_data in sorted_tags:
            size = r_data["size"]
            size_str = self.utils.convert_file_sizes(size)
            percent = (size / total_size * 100) if total_size else 0.0
            bar_len = int((percent / 100) * 30)
            ascii_bar = f"{self.yellow}{'#' * bar_len}{self.endc}{' ' * (30 - bar_len)}"
            print(f"{tag:<12} [{ascii_bar}] {size_str:>10} ({percent:>5.1f}%)")

    def run(self) -> None:
        """Main execution logic for stats."""
        self.view_process.message("Gathering statistics")
        data = self._get_stats()
        self.view_process.done()

        if not data["repositories"]:
            print(f"\n{self.red}No statistics available.{self.endc}")
            return

        # Handle JSON output
        if self.options.get("option_json"):
            json_data = {
                "summary": data["repositories"],
                "total_count": data["total_count"],
                "total_size": data["total_size"],
                "total_size_human": self.utils.convert_file_sizes(data["total_size"])
            }
            print(json.dumps(json_data, indent=4))
            return

        # Normal display
        print(f"\n{self.bold}System Statistics{self.endc}")
        print("=" * (self.columns - 1))

        repos = data["repositories"]
        total_count: int = data["total_count"]
        total_size: int = data["total_size"]

        self._display_packages_per_repo(repos, total_count)
        print("-" * (self.columns - 1))
        total_size_str = self.utils.convert_file_sizes(total_size)
        print(f"{'Total':<12} {'':<32} {total_count:>5} pkgs (100.0%) | {total_size_str:>10}")

        self._display_disk_usage_per_repo(repos, total_size)
        print("-" * (self.columns - 1))
        print(f"{'Total':<12} {'':<32} {total_size_str:>10} (100.0%)")

        # Handle --top N
        top_limit = self.options.get("option_top")
        if top_limit:
            self._display_top_packages(data["packages"], top_limit)

        logger.info("Statistics display completed.")
