from typing import Type, TypeVar, cast, ParamSpec

from faststream._internal.broker import BrokerUsecase
from faststream.asgi import AsgiFastStream
from faststream.prometheus import PrometheusMiddleware
from prometheus_client import make_asgi_app

from .._logger import logger
from ..core import MetricsExporter

M_PrometheusMiddleware = TypeVar("M_PrometheusMiddleware", bound=PrometheusMiddleware)
P = ParamSpec("P")


class _MetricsMiddlewareType(PrometheusMiddleware):
    metrics_exporter: MetricsExporter

    def __init__(self, metrics: MetricsExporter, *args: P.args, **kwargs: P.kwargs) -> None:
        super().__init__(*args, **kwargs)


_BROKER_MIDDLEWARE_MAP: dict[Type[BrokerUsecase], Type[_MetricsMiddlewareType]] = {}


def create_middleware_cls(base_cls: Type[M_PrometheusMiddleware], broker_name: str) -> Type[_MetricsMiddlewareType]:
    """
    Создает динамический класс Middleware, наследуясь от специфичного для брокера
    PrometheusMiddleware (например, RabbitPrometheusMiddleware).
    """
    cls_name = f"{broker_name}PrometheusMiddlewareCustom"

    class CustomMiddleware(base_cls):  # type: ignore[valid-type, misc]
        def __init__(self, metrics: MetricsExporter):
            self.metrics_exporter = metrics
            super().__init__(registry=metrics.get_registry(), metrics_prefix=metrics.prefix)

    CustomMiddleware.__name__ = cls_name
    CustomMiddleware.__qualname__ = cls_name
    return cast(Type[_MetricsMiddlewareType], CustomMiddleware)


def register_broker_middleware(
    broker_module: str,
    broker_cls_name: str,
    middleware_module: str,
    middleware_cls_name: str,
    alias: str,
) -> None:
    """
    Безопасная регистрация
    """
    try:
        br_mod = __import__(broker_module, fromlist=[broker_cls_name])
        mw_mod = __import__(middleware_module, fromlist=[middleware_cls_name])

        broker_cls = getattr(br_mod, broker_cls_name)
        middleware_cls = getattr(mw_mod, middleware_cls_name)

        _BROKER_MIDDLEWARE_MAP[broker_cls] = create_middleware_cls(middleware_cls, alias)
    except ImportError:
        pass


def register_custom_broker(
    broker_cls: Type[BrokerUsecase],
    middleware_cls: Type[M_PrometheusMiddleware],
    alias: str,
) -> None:
    """
    Функция для ручной регистрации пользовательских брокеров.
    """
    _BROKER_MIDDLEWARE_MAP[broker_cls] = create_middleware_cls(middleware_cls, alias)


register_broker_middleware(
    "faststream.rabbit",
    "RabbitBroker",
    "faststream.rabbit.prometheus",
    "RabbitPrometheusMiddleware",
    "Rabbit",
)
register_broker_middleware(
    "faststream.kafka",
    "KafkaBroker",
    "faststream.kafka.prometheus",
    "KafkaPrometheusMiddleware",
    "Kafka",
)
register_broker_middleware(
    "faststream.redis",
    "RedisBroker",
    "faststream.redis.prometheus",
    "RedisPrometheusMiddleware",
    "Redis",
)
register_broker_middleware(
    "faststream.confluent",
    "KafkaBroker",
    "faststream.confluent.prometheus",
    "KafkaPrometheusMiddleware",
    "Confluent",
)
register_broker_middleware(
    "faststream.nats",
    "NatsBroker",
    "faststream.nats.prometheus",
    "NatsPrometheusMiddleware",
    "Nats",
)


def setup_broker_metrics(broker: BrokerUsecase, metrics: MetricsExporter) -> bool:
    """
    Устанавливает метрики в брокер.
    """
    broker_type = type(broker)
    middleware_cls = _BROKER_MIDDLEWARE_MAP.get(broker_type)

    if not middleware_cls:
        for b_cls, m_cls in _BROKER_MIDDLEWARE_MAP.items():
            if isinstance(broker, b_cls):
                middleware_cls = m_cls
                break

    if not middleware_cls:
        available = [k.__name__ for k in _BROKER_MIDDLEWARE_MAP.keys()]
        raise ValueError(
            f"Unsupported broker type: {broker_type.__name__}. " f"Installed drivers support: {', '.join(available)}"
        )

    for mw in broker.middlewares:
        if isinstance(mw, middleware_cls):
            existing_exporter = getattr(mw, "metrics_exporter", None)
            if existing_exporter is metrics:
                logger.debug(f"Metrics middleware for {broker_type.__name__} (id={id(metrics)}) already configured.")
                return False

    logger.info(f"Adding metrics middleware to {broker_type.__name__}")
    broker.insert_middleware(middleware_cls(metrics=metrics))
    return True


def setup_faststream_metrics(app: AsgiFastStream, metrics: MetricsExporter, path: str = "/metrics") -> None:
    if not app.broker:
        raise ValueError("FastStream app has no broker configured.")

    broker: BrokerUsecase = app.broker
    is_newly_installed = setup_broker_metrics(broker, metrics)

    if not is_newly_installed:
        logger.debug("The middleware has already been installed before")
        return

    is_path_taken = any(route == path for route, handler in app.routes)

    if is_path_taken:
        raise ValueError(
            f"Cannot expose metrics at '{path}'. This path is already occupied. "
            f"If adding multiple registries, specify a distinct 'path'."
        )

    logger.info(f"Exposing metrics at {path}")
    app.routes.append((path, make_asgi_app(metrics.get_registry())))
