"""Platzhalter-Kategorisierer für die PBI Documentation by Oliver Gropp.

Kategorisiert Platzhalter abhängig von der Verbindungsmethode, indem
die Verfügbarkeitsmatrix mit den Mapping-Regeln abgeglichen wird.
"""
from __future__ import annotations

from core.models import CategorySummary, Placeholder, PlaceholderCategory
from core.mapping_config import ALWAYS_MANUAL, AVAILABILITY_MATRIX, MAPPING_RULES


class PlaceholderCategorizer:
    """Kategorisiert Platzhalter basierend auf Verbindungsmethode."""

    def __init__(
        self,
        mapping_rules: dict[str, str] | None = None,
        always_manual: list[str] | None = None,
        availability_matrix: dict[str, list[str]] | None = None,
    ) -> None:
        self._mapping_rules = mapping_rules if mapping_rules is not None else MAPPING_RULES
        self._always_manual = always_manual if always_manual is not None else ALWAYS_MANUAL
        self._availability_matrix = (
            availability_matrix if availability_matrix is not None else AVAILABILITY_MATRIX
        )

    # ------------------------------------------------------------------
    # Public API
    # ------------------------------------------------------------------

    def categorize(
        self,
        placeholders: list[Placeholder],
        connection_type: str,
    ) -> list[PlaceholderCategory]:
        """Kategorisiert Platzhalter basierend auf Verbindungsmethode.

        Logik pro Platzhalter:
        - In ALWAYS_MANUAL → category="manuell"
        - In MAPPING_RULES und Metadaten-Root verfügbar → category="automatisch"
        - In MAPPING_RULES aber Metadaten-Root nicht verfügbar → category="manuell"
        - Sonst → category="manuell"
        """
        categories: list[PlaceholderCategory] = []

        for ph in placeholders:
            name = ph.name

            # 1) Immer manuell?
            if name in self._always_manual:
                categories.append(
                    PlaceholderCategory(
                        placeholder_name=name,
                        category="manuell",
                        available_in=[],
                    )
                )
                continue

            # 2) Zuordnungsregel vorhanden?
            if name in self._mapping_rules:
                path = self._mapping_rules[name]
                root = self._extract_root(path)
                available_in = self._get_available_connections(root)

                if root in self._availability_matrix.get(connection_type, []):
                    category = "automatisch"
                else:
                    category = "manuell"

                categories.append(
                    PlaceholderCategory(
                        placeholder_name=name,
                        category=category,
                        available_in=available_in,
                    )
                )
                continue

            # 3) Kein Mapping bekannt → manuell
            categories.append(
                PlaceholderCategory(
                    placeholder_name=name,
                    category="manuell",
                    available_in=[],
                )
            )

        return categories

    def get_summary(
        self,
        categories: list[PlaceholderCategory],
    ) -> CategorySummary:
        """Erstellt Zusammenfassung der Kategorisierung."""
        auto_count = 0
        manual_count = 0
        partial_count = 0

        for cat in categories:
            if cat.category == "automatisch":
                auto_count += 1
            elif cat.category == "teilweise":
                partial_count += 1
            else:
                manual_count += 1

        return CategorySummary(
            auto_count=auto_count,
            manual_count=manual_count,
            partial_count=partial_count,
            details=categories,
        )

    # ------------------------------------------------------------------
    # Internal helpers
    # ------------------------------------------------------------------

    @staticmethod
    def _extract_root(path: str) -> str:
        """Extrahiert das Root-Attribut aus einem Metadaten-Pfad.

        Beispiele:
          - "report_name"                → "report_name"
          - "refresh_schedule.frequency" → "refresh_schedule"
          - "data_sources[*].name"       → "data_sources"
          - "measures[*].expression"     → "measures"
        """
        # Abschneiden bei '[' (Listen-Pfade wie "data_sources[*].name")
        root = path.split("[")[0]
        # Abschneiden bei '.' (verschachtelte Pfade wie "refresh_schedule.frequency")
        root = root.split(".")[0]
        return root

    def _get_available_connections(self, root: str) -> list[str]:
        """Gibt alle Verbindungstypen zurück, bei denen das Root-Attribut verfügbar ist."""
        return [
            conn_type
            for conn_type, available in self._availability_matrix.items()
            if root in available
        ]
