from __future__ import annotations

import importlib
import logging
import os
from typing import Optional

from .base import CaptchaSolver

logger = logging.getLogger("captcha_router")


class CaptchaRouter:
    """Factory/registry for captcha solvers with pluggable provider support."""

    _providers: dict[str, type[CaptchaSolver]] = {}
    _provider_api_key_env: dict[str, str] = {}
    _primary_provider_by_class: dict[type[CaptchaSolver], str] = {}
    _canonical_provider_name: dict[str, str] = {}
    _builtin_loaded = False
    _external_loaded = False

    @staticmethod
    def _normalize_provider_name(name: str) -> str:
        return name.strip().lower()

    @classmethod
    def register_provider(
        cls,
        provider_name: str,
        provider_class: type[CaptchaSolver],
        *,
        aliases: tuple[str, ...] = (),
        api_key_env: Optional[str] = None,
        override: bool = False,
    ) -> None:
        """Register a provider class under one or more names."""

        if not issubclass(provider_class, CaptchaSolver):
            raise TypeError("provider_class must inherit from CaptchaSolver")

        names = [provider_name, *aliases]
        normalized_names = [cls._normalize_provider_name(name) for name in names]
        primary_name = cls._normalize_provider_name(provider_name)
        existing_primary = cls._primary_provider_by_class.get(provider_class)
        if existing_primary and not override:
            primary_name = existing_primary
        else:
            cls._primary_provider_by_class[provider_class] = primary_name

        for name in normalized_names:
            existing = cls._providers.get(name)
            if existing and existing is not provider_class and not override:
                raise ValueError(
                    f"Provider name '{name}' is already registered for {existing.__name__}"
                )
            cls._providers[name] = provider_class
            cls._canonical_provider_name[name] = primary_name
            if api_key_env:
                cls._provider_api_key_env[name] = api_key_env

    @classmethod
    def provider(
        cls,
        provider_name: str,
        *aliases: str,
        api_key_env: Optional[str] = None,
        override: bool = False,
    ):
        """Decorator to register provider classes on import."""

        def decorator(provider_class: type[CaptchaSolver]) -> type[CaptchaSolver]:
            cls.register_provider(
                provider_name,
                provider_class,
                aliases=aliases,
                api_key_env=api_key_env,
                override=override,
            )
            return provider_class

        return decorator

    @classmethod
    def _load_builtin_providers(cls) -> None:
        if cls._builtin_loaded:
            return
        importlib.import_module(".providers", package=__package__)
        cls._builtin_loaded = True

    @classmethod
    def _load_external_provider_modules(cls) -> None:
        if cls._external_loaded:
            return

        module_list = os.environ.get("CAPTCHA_PROVIDER_MODULES", "")
        modules = [item.strip() for item in module_list.split(",") if item.strip()]

        for module_name in modules:
            importlib.import_module(module_name)
            logger.info("Loaded captcha provider module: %s", module_name)

        cls._external_loaded = True

    @classmethod
    def _ensure_registry_populated(cls) -> None:
        cls._load_builtin_providers()
        cls._load_external_provider_modules()

    @classmethod
    def list_providers(cls) -> list[str]:
        """Return sorted list of known provider names/aliases."""

        cls._ensure_registry_populated()
        return sorted(cls._providers.keys())

    @classmethod
    def get_supported_task_kinds(cls, provider_name: str) -> list[str]:
        """Return supported captcha task kinds for a specific provider name/alias."""
        cls._ensure_registry_populated()
        key = cls._normalize_provider_name(provider_name)
        provider_class = cls._providers.get(key)
        if not provider_class:
            raise ValueError(
                f"Unknown captcha provider: {provider_name}. Available: {cls.list_providers()}"
            )
        return provider_class.supported_task_kinds()

    @classmethod
    def list_provider_capabilities(cls, include_aliases: bool = False) -> dict[str, list[str]]:
        """Return provider -> supported captcha kinds map."""
        cls._ensure_registry_populated()

        if include_aliases:
            return {
                name: cls._providers[name].supported_task_kinds()
                for name in sorted(cls._providers.keys())
            }

        capabilities: dict[str, list[str]] = {}
        for name, provider_class in cls._providers.items():
            canonical_name = cls._canonical_provider_name.get(name, name)
            capabilities[canonical_name] = provider_class.supported_task_kinds()
        return {name: capabilities[name] for name in sorted(capabilities.keys())}

    @classmethod
    def list_supported_task_kinds(cls) -> list[str]:
        """Return union of supported captcha kinds across registered providers."""
        cls._ensure_registry_populated()
        kinds: set[str] = set()
        for provider_class in set(cls._providers.values()):
            kinds.update(provider_class.supported_task_kinds())
        return sorted(kinds)

    @classmethod
    def get_solver(
        cls,
        provider_name: Optional[str] = None,
        api_key: Optional[str] = None,
        **kwargs,
    ) -> CaptchaSolver:
        """Get a captcha solver instance.

        Args:
            provider_name: Provider name. Defaults to env var CAPTCHA_PROVIDER or 'anticaptcha'.
            api_key: API key. Defaults to provider-specific env var (or CAPTCHA_API_KEY fallback).
            **kwargs: Additional config passed to provider.

        Returns:
            An instance of a CaptchaSolver implementation.
        """

        cls._ensure_registry_populated()

        selected_provider = provider_name or os.environ.get("CAPTCHA_PROVIDER", "anticaptcha")
        provider_key = cls._normalize_provider_name(selected_provider)

        provider_class = cls._providers.get(provider_key)
        if not provider_class:
            raise ValueError(
                f"Unknown captcha provider: {selected_provider}. Available: {cls.list_providers()}"
            )

        if not api_key:
            env_name = kwargs.pop("api_key_env", None) or cls._provider_api_key_env.get(provider_key)
            if env_name:
                api_key = os.environ.get(env_name)
            if not api_key:
                api_key = os.environ.get("CAPTCHA_API_KEY")

        if not api_key:
            raise ValueError(
                f"API key not found for provider {selected_provider}. "
                "Set provider env key or pass api_key explicitly."
            )

        logger.info("Initializing Captcha Provider: %s", provider_key)
        return provider_class(api_key, **kwargs)
