"""Index aller pacman-bekannten Namen, gegen die Dotfolder gematcht werden."""
from __future__ import annotations

import re
import subprocess
from dataclasses import dataclass, field
from functools import lru_cache
from pathlib import Path

# Pfade, deren Basename ein guter Hint auf einen App-Namen ist
_BIN_PREFIXES = ("/usr/bin/", "/usr/local/bin/", "/usr/lib/")


def _normalize(name: str) -> str:
    """App-Namen für Fuzzy-Match normalisieren: lowercase, ohne -_. Trennzeichen."""
    return re.sub(r"[-_.\s]", "", name.lower())


@dataclass
class PackageIndex:
    """Set von normalisierten Tokens (Paketnamen + Binary-Namen),
    gegen die ein Dotfolder gematcht werden kann."""

    tokens: set[str] = field(default_factory=set)
    package_names: set[str] = field(default_factory=set)

    def matches(self, dirname: str) -> str | None:
        """Gibt den Original-Paketnamen zurück wenn ein Match gefunden wird."""
        norm = _normalize(dirname)
        if not norm:
            return None
        if norm in self.tokens:
            for pkg in self.package_names:
                if _normalize(pkg) == norm:
                    return pkg
            return norm
        # Substring-Match (eine Richtung) - z.B. "discord-canary" matcht "discord"
        for pkg in self.package_names:
            npkg = _normalize(pkg)
            if not npkg or len(npkg) < 3:
                continue
            if npkg in norm or norm in npkg:
                return pkg
        return None


@lru_cache(maxsize=1)
def build_index() -> PackageIndex:
    """Index einmalig bauen, danach gecached. Liest pacman -Ql."""
    idx = PackageIndex()
    try:
        result = subprocess.run(
            ["pacman", "-Ql"],
            capture_output=True,
            text=True,
            check=True,
            timeout=30,
        )
    except (subprocess.CalledProcessError, subprocess.TimeoutExpired, FileNotFoundError):
        return idx

    for line in result.stdout.splitlines():
        # Format: "<pkgname> <filepath>"
        parts = line.split(" ", 1)
        if len(parts) != 2:
            continue
        pkg, path = parts
        idx.package_names.add(pkg)
        idx.tokens.add(_normalize(pkg))

        # Auch Binary-Basenames als Tokens (z.B. "code" für "code-oss")
        for prefix in _BIN_PREFIXES:
            if path.startswith(prefix):
                tail = path[len(prefix):].rstrip("/")
                if "/" in tail:
                    continue  # Subverzeichnisse überspringen, nur direkte Binaries
                if tail:
                    idx.tokens.add(_normalize(tail))
                break

    return idx
