import logging.config
from typing import Dict

from pydantic import BaseSettings

# noinspection PyUnresolvedReferences
from .application import Bali
from .cache import cache
from .cache_memoize import cache_memoize
from .db import db, transaction
# noinspection PyUnresolvedReferences
from .routing import APIRouter

# Bind transaction to db
setattr(db, 'transaction', transaction)


class Settings(BaseSettings):
    ENABLED_RPC_LOGGING: str = False
    AMQP_CONFIGS: Dict[str, Dict[str, str]] = {
        'default':
            {
                'AMQP_SERVER_ADDRESS': 'amqp://user:passwd@host:port',
                # It will be used if you defined EXCHANGE_NAME, else
                # BALI_EXCHANGE will be used
                # 'EXCHANGE_NAME': 'event_default_exchange',
                # It will be used if you set queue name,else queue name
                # will be generated by BALI_QUEUE and event_type
                # 'QUEUE_NAME': 'event_default_queue',
                # It will used if you set routing_key,else it
                # will be generated by BALI_ROUTING_KEY and
                # event_type
                # 'ROUTING_KEY': 'event_default_routing_key'
            }
    }
    # You can map event_type to amqp, or it will be map to default amqp
    # You can map event_type to more than one amqp split by ','
    # EVENT_TYPE_TO_AMQP = {'test0': 'default', 'test1': 'default,others'}
    EVENT_TYPE_TO_AMQP: Dict[str, str] = {}
    BALI_QUEUE = 'event_default_queue'
    BALI_EXCHANGE = 'event_default_exchange'
    BALI_ROUTING_KEY = 'event_default_routing_key'


_settings = Settings()


def initialize(settings):
    # update basic settings
    if not hasattr(settings, 'ENABLED_RPC_LOGGING'):
        settings.Config.__setattr__(settings, 'ENABLED_RPC_LOGGING', False)

    # load custom settings
    global _settings
    _settings = settings

    # initialize db connections, default enabled db
    # can be disabled by `DISABLE_DB_CONNECTION` settings
    if not getattr(settings, 'DISABLE_DB_CONNECTION', False):
        if not hasattr(settings, 'SQLALCHEMY_DATABASE_URI'):
            raise Exception(
                'Initialized db connection without `SQLALCHEMY_DATABASE_URI` setting'
            )

        db.connect(settings.SQLALCHEMY_DATABASE_URI)

    # initialize cache connections, default enabled db
    # can be disabled by `DISABLED_DB_CONNECTION` settings
    # cache prefix can be custom by `CACHE_PREFIX`
    if not getattr(settings, 'DISABLE_CACHE_CONNECTION', False):
        if not hasattr(settings, 'CACHE_ADDRESS'):
            raise Exception(
                'Initialized cache connection without `CACHE_ADDRESS` setting'
            )

        if not hasattr(settings, 'CACHE_PASSWORD'):
            raise Exception(
                'Initialized cache connection without `CACHE_PASSWORD` setting'
            )

        cache.connect(
            settings.CACHE_ADDRESS,
            password=settings.CACHE_PASSWORD,
            prefix=getattr(
                settings, 'CACHE_PREFIX', f'{settings.SERVER_NAME}_service'
            )
        )
    if hasattr(settings, 'LOGGING_CONFIG'):
        logging.config.dictConfig(settings.LOGGING_CONFIG)

    if not hasattr(settings, 'BALI_QUEUE'):
        settings.Config.__setattr__(settings, 'BALI_QUEUE', '{}.events')

    if not hasattr(settings, 'BALI_EXCHANGE'):
        settings.Config.__setattr__(settings, 'BALI_EXCHANGE', 'ms.events')

    if not hasattr(settings, 'BALI_ROUTING_KEY'):
        settings.Config.__setattr__(settings, 'BALI_ROUTING_KEY', '{}.routing')
    if not hasattr(settings, 'EVENT_TYPE_TO_AMQP'):
        settings.Config.__setattr__(settings, 'EVENT_TYPE_TO_AMQP', {})
