import asyncio
from typing import Dict

from aiohttp import web
from smb.common.http_client import HttpClient
from smb.common.multiruntime.lib.io import setup_filesystem

from maps_adv.common import email_sender
from maps_adv.common.aiosup import SupClient, ThrottlePolicies
from maps_adv.common.aioyav import YavClient
from maps_adv.common.lasagna import Lasagna
from maps_adv.common.yasms import YasmsClient
from maps_adv.geosmb.clients.bvm import BvmClient
from maps_adv.geosmb.clients.geosearch import GeoSearchClient
from maps_adv.geosmb.doorman.client import DoormanClient
from maps_adv.geosmb.tuner.client import TunerClient
from maps_adv.geosmb.clients.notify_me import NotifyMeClient

from .api import create as create_api
from .domain import Domain
from .notification_router import NotificationRouter
from .notification_router_v3 import NotificationRouterV3

setup_filesystem("maps_adv/geosmb/telegraphist/server/")


class Application(Lasagna):
    SWIM_ENGINE_CLS = None

    async def _setup_layers(self, db: None) -> web.Application:
        clients = await self._setup_clients()

        notification_router = NotificationRouter(
            doorman_client=clients["doorman_client"],
            email_client=clients["email_client"],
            yasms=clients["yasms"],
            yav_client=clients["yav_client"],
            sup_client=clients["sup_client"],
            tuner_client=clients["tuner_client"],
            # TODO нужно как-то загружать эти шаблоны из конфига.
            email_template_codes={
                "client": {
                    "order_created": self.config["EMAIL_TEMPLATE_CODE_ORDER_CREATED"],
                    "order_reminder": self.config["EMAIL_TEMPLATE_CODE_ORDER_REMINDER"],
                    "order_changed": self.config["EMAIL_TEMPLATE_CODE_ORDER_CHANGED"],
                    "order_cancelled": self.config[
                        "EMAIL_TEMPLATE_CODE_ORDER_CANCELLED"
                    ],
                },
                "business": {
                    "order_created_for_business": self.config[
                        "EMAIL_TEMPLATE_CODE_ORDER_CREATED_FOR_BUSINESS"
                    ],
                    "order_cancelled_for_business": self.config[
                        "EMAIL_TEMPLATE_CODE_ORDER_CANCELLED_FOR_BUSINESS"
                    ],
                    "order_changed_for_business": self.config[
                        "EMAIL_TEMPLATE_CODE_ORDER_CHANGED_FOR_BUSINESS"
                    ],
                    "certificate_expiring": self.config[
                        "EMAIL_TEMPLATE_CODE_CERTIFICATE_EXPIRING"
                    ],
                    "certificate_expired": self.config[
                        "EMAIL_TEMPLATE_CODE_CERTIFICATE_EXPIRED"
                    ],
                    "certificate_connect_payment": self.config[
                        "EMAIL_TEMPLATE_CODE_CERTIFICATE_CONNECT_PAYMENT"
                    ],
                    "certificate_rejected": self.config[
                        "EMAIL_TEMPLATE_CODE_CERTIFICATE_REJECTED"
                    ],
                    "first_certificate_approved": self.config[
                        "EMAIL_TEMPLATE_CODE_FIRST_CERTIFICATE_APPROVED"
                    ],
                    "subsequent_certificate_approved": self.config[
                        "EMAIL_TEMPLATE_CODE_SUBSEQUENT_CERTIFICATE_APPROVED"
                    ],
                    "certificate_created": self.config[
                        "EMAIL_TEMPLATE_CODE_CERTIFICATE_CREATED"
                    ],
                    "certificate_purchased": self.config[
                        "EMAIL_TEMPLATE_CODE_CERTIFICATE_PURCHASED"
                    ],
                    "request_created_for_business": self.config[
                        "EMAIL_TEMPLATE_CODE_REQUEST_CREATED_FOR_BUSINESS"
                    ],
                },
            },
            limit_recipients=self.config["LIMIT_RECIPIENTS"],
            yav_secret_id=self.config["YAV_SECRET_ID"],
        )
        notification_router_v3 = NotificationRouterV3(
            email_client=clients["email_client"],
            telegram_client=clients["notify_me"],
            yasms=clients["yasms"],
            email_template_codes={
                "cart_order_created": self.config[
                    "EMAIL_TEMPLATE_CODE_CART_ORDER_CREATED"],
                "request_created_for_business": self.config[
                    "EMAIL_TEMPLATE_CODE_REQUEST_CREATED_FOR_BUSINESS"]
            },
            limit_recipients=self.config["LIMIT_RECIPIENTS"],
            yav_client=clients["yav_client"],
            yav_secret_id=self.config["YAV_SECRET_ID"],
        )
        domain = Domain(
            purchased_certificate_template_code=self.config[
                "PURCHASED_CERTIFICATE_EMAIL_TEMPLATE_CODE"
            ],
            limit_recipients=self.config["LIMIT_RECIPIENTS"],
            email_client=clients["email_client"],
            yasms=clients["yasms"],
            notify_me=clients["notify_me"],
            bvm_client=clients["bvm_client"],
            geosearch_client=clients["geosearch_client"],
            doorman_client=clients["doorman_client"],
            notification_router=notification_router,
            notification_router_v3=notification_router_v3,
        )

        _api = create_api(domain)
        _api.on_shutdown.append(
            lambda _: asyncio.gather(*[client.close() for client in clients.values()])
        )

        return _api

    async def _setup_clients(self) -> Dict[str, HttpClient]:
        return {
            "doorman_client": await DoormanClient(
                url=self.config["DOORMAN_URL"],
                tvm=self.tvm,
                tvm_destination=self.config["DOORMAN_TVM_ID"],
            ),
            "email_client": await email_sender.Client(
                account_slug=self.config["EMAIL_CLIENT_ACCOUNT_SLUG"],
                account_token=self.config["EMAIL_CLIENT_ACCOUNT_TOKEN"],
                url=self.config["EMAIL_CLIENT_API_URL"],
            ),
            "yasms": await YasmsClient(
                url=self.config["YASMS_URL"],
                sender=self.config["YASMS_SENDER"],
                tvm=self.tvm,
                tvm_destination="yasms",
            ),
            "bvm_client": await BvmClient(self.config["BVM_URL"]),
            "geosearch_client": await GeoSearchClient(
                url=self.config["GEOSEARCH_URL"],
                tvm=self.tvm,
                tvm_destination="geosearch",
            ),
            "yav_client": await YavClient(self.config["YAV_TOKEN"]),
            "sup_client": await SupClient(
                url=self.config["SUP_URL"],
                auth_token=self.config["SUP_OAUTH_TOKEN"],
                project=self.config["SUP_PROJECT"],
                throttle_policies=ThrottlePolicies(
                    device_id=self.config["SUP_THROTTLE_POLICY_NAME"]
                ),
            ),
            "tuner_client": await TunerClient(
                url=self.config["TUNER_URL"], tvm=self.tvm, tvm_destination="tuner"
            ),
            "notify_me": await NotifyMeClient(
                url=self.config["NOTIFY_ME_URL"],
            ),
        }
