"""
Registry pour la détection automatique des stores.

Le Registry maintient une liste de tous les stores disponibles et
peut détecter automatiquement quel store correspond à une URL donnée.
"""

from typing import Optional

from pricewatch.app.core.logging import get_logger
from pricewatch.app.stores.base import BaseStore

logger = get_logger("core.registry")


class StoreRegistry:
    """
    Registry central pour tous les stores.

    Permet d'enregistrer des stores et de détecter automatiquement
    le bon store depuis une URL via la méthode match().

    Justification technique:
    - Pattern Registry pour découpler la détection des stores du code métier
    - Extensible: ajouter un nouveau store = juste register() un nouvel objet
    - Pas de dépendances hardcodées entre modules
    """

    def __init__(self):
        """Initialise un registry vide."""
        self._stores: list[BaseStore] = []
        logger.debug("Registry initialisé")

    def register(self, store: BaseStore) -> None:
        """
        Enregistre un nouveau store dans le registry.

        Args:
            store: Instance de BaseStore à enregistrer
        """
        if not isinstance(store, BaseStore):
            raise TypeError(f"Expected BaseStore, got {type(store)}")

        # Éviter les doublons
        if any(s.store_id == store.store_id for s in self._stores):
            logger.warning(f"Store '{store.store_id}' déjà enregistré, remplacement")
            self._stores = [s for s in self._stores if s.store_id != store.store_id]

        self._stores.append(store)
        logger.info(f"Store enregistré: {store.store_id}")

    def unregister(self, store_id: str) -> bool:
        """
        Retire un store du registry.

        Args:
            store_id: ID du store à retirer

        Returns:
            True si le store a été retiré, False s'il n'était pas présent
        """
        initial_count = len(self._stores)
        self._stores = [s for s in self._stores if s.store_id != store_id]
        removed = len(self._stores) < initial_count

        if removed:
            logger.info(f"Store désenregistré: {store_id}")
        else:
            logger.warning(f"Store non trouvé pour désenregistrement: {store_id}")

        return removed

    def get_store(self, store_id: str) -> Optional[BaseStore]:
        """
        Récupère un store par son ID.

        Args:
            store_id: ID du store à récupérer

        Returns:
            Instance du store ou None si non trouvé
        """
        for store in self._stores:
            if store.store_id == store_id:
                return store
        return None

    def detect_store(self, url: str) -> Optional[BaseStore]:
        """
        Détecte automatiquement le store correspondant à une URL.

        Args:
            url: URL à analyser

        Returns:
            Store avec le meilleur score, ou None si aucun match

        Justification technique:
        - Teste tous les stores enregistrés avec leur méthode match()
        - Retourne celui avec le score le plus élevé (> 0)
        - Permet de gérer les ambiguïtés (ex: sous-domaines multiples)
        """
        if not url or not url.strip():
            logger.warning("URL vide fournie pour détection")
            return None

        if not self._stores:
            logger.warning("Aucun store enregistré dans le registry")
            return None

        best_store: Optional[BaseStore] = None
        best_score = 0.0

        logger.debug(f"Détection du store pour: {url}")

        for store in self._stores:
            try:
                score = store.match(url)
                logger.debug(f"  {store.store_id}: score={score:.2f}")

                if score > best_score:
                    best_score = score
                    best_store = store

            except Exception as e:
                logger.error(f"Erreur lors du match de {store.store_id}: {e}")
                continue

        if best_store:
            logger.info(
                f"Store détecté: {best_store.store_id} (score={best_score:.2f})"
            )
        else:
            logger.warning(f"Aucun store trouvé pour: {url}")

        return best_store

    def list_stores(self) -> list[str]:
        """
        Liste tous les stores enregistrés.

        Returns:
            Liste des IDs de stores
        """
        return [store.store_id for store in self._stores]

    def __len__(self) -> int:
        """Retourne le nombre de stores enregistrés."""
        return len(self._stores)

    def __repr__(self) -> str:
        stores_list = ", ".join(self.list_stores())
        return f"<StoreRegistry stores=[{stores_list}]>"


# Instance globale du registry
# Les stores s'y enregistreront lors de leur import
_global_registry = StoreRegistry()


def get_registry() -> StoreRegistry:
    """
    Retourne l'instance globale du registry.

    Returns:
        Registry singleton
    """
    return _global_registry


def register_store(store: BaseStore) -> None:
    """
    Enregistre un store dans le registry global.

    Args:
        store: Instance de BaseStore
    """
    _global_registry.register(store)


def detect_store(url: str) -> Optional[BaseStore]:
    """
    Détecte le store depuis le registry global.

    Args:
        url: URL à analyser

    Returns:
        Store détecté ou None
    """
    return _global_registry.detect_store(url)
