from dataclasses import dataclass

import logging
from typing import Annotated, Awaitable, Callable

from fast_depends import Depends
from faststream import Context
from faststream.rabbit import RabbitExchange, RabbitBroker

from cattle_grid.config.rewrite import RewriteConfiguration
from cattle_grid.model.extension import MethodInformationModel
from cattle_grid.model.lookup import LookupMethod
from cattle_grid.app import access_methods, app_globals
from cattle_grid.tools.faststream import custom_wait_for_reply


logger = logging.getLogger(__name__)

Transformer = Annotated[
    Callable[..., Awaitable[dict]], Depends(access_methods.get_transformer)
]
"""The transformer loaded from extensions"""

LookupAnnotation = Annotated[LookupMethod, Depends(access_methods.get_lookup)]
"""The lookup method loaded from extensions"""


InternalExchange = Annotated[
    RabbitExchange, Depends(access_methods.get_internal_exchange)
]
"""The interal activity exchange"""

ActivityExchange = Annotated[
    RabbitExchange, Depends(access_methods.get_activity_exchange)
]
"""The activity exchange"""

AccountExchange = Annotated[
    RabbitExchange, Depends(access_methods.get_account_exchange)
]
"""The account exchange"""

CorrelationId = Annotated[str, Context("message.correlation_id")]
"""The correlation id of the message"""

MethodInformation = Annotated[
    list[MethodInformationModel], Depends(access_methods.get_method_information)
]
"""Returns the information about the methods that are a part of the exchange"""


def get_rewrite_rules():
    return app_globals.rewrite_rules


RewriteRules = Annotated[RewriteConfiguration, Depends(get_rewrite_rules)]
"""Rewturns the rewrite configuration"""


class BasePublisherClass:
    async def __call__(self, *args, **kwargs):
        kwargs_updated = {**kwargs}
        kwargs_updated.update(
            dict(exchange=self.exchange, correlation_id=self.correlation_id)
        )
        return await self.broker.publish(*args, **kwargs_updated)


class BaseRequesterClass:
    async def __call__(self, *args, **kwargs):
        kwargs_updated = {**kwargs}
        kwargs_updated.update(
            dict(exchange=self.exchange, correlation_id=self.correlation_id)
        )
        try:
            return await custom_wait_for_reply(self.broker, *args, **kwargs_updated)
        except Exception as e:
            logger.exception(e)
            return {}


@dataclass
class ActivityExchangePublisherClass(BasePublisherClass):
    correlation_id: CorrelationId
    exchange: ActivityExchange
    broker: RabbitBroker = Context()


@dataclass
class ActivityExchangeRequesterClass(BaseRequesterClass):
    correlation_id: CorrelationId
    exchange: ActivityExchange
    broker: RabbitBroker = Context()


@dataclass
class InternalExchangePublisherClass(BasePublisherClass):
    correlation_id: CorrelationId
    exchange: InternalExchange
    broker: RabbitBroker = Context()


@dataclass
class AccountExchangePublisherClass(BasePublisherClass):
    correlation_id: CorrelationId
    exchange: AccountExchange
    broker: RabbitBroker = Context()


@dataclass
class InternalExchangeRequesterClass(BaseRequesterClass):
    correlation_id: CorrelationId
    exchange: InternalExchange
    broker: RabbitBroker = Context()
