from importlib import import_module

from cached_property import cached_property
from flask import Flask
from flask_babelex import Babel

from opwen_email_client.domain.email.client import HttpEmailServerClient
from opwen_email_client.domain.email.client import LocalEmailServerClient
from opwen_email_client.domain.email.sql_store import SqliteEmailStore
from opwen_email_client.domain.email.sync import AzureSync
from opwen_email_client.util.serialization import JsonSerializer
from opwen_email_client.webapp.cache import cache
from opwen_email_client.webapp.config import AppConfig
from opwen_email_client.webapp.forms.login import LoginForm
from opwen_email_client.webapp.forms.login import RegisterForm
from opwen_email_client.webapp.login import FlaskLoginUserStore
from opwen_email_client.webapp.mkwvconf import blueprint as mkwvconf
from opwen_email_client.webapp.security import security


class Ioc:
    @cached_property
    def serializer(self):
        return JsonSerializer()

    @cached_property
    def email_server_client(self):
        if AppConfig.TESTING:
            return LocalEmailServerClient()

        return HttpEmailServerClient(
            compression=AppConfig.COMPRESSION,
            hostname=AppConfig.EMAIL_SERVER_HOSTNAME,
            client_id=AppConfig.CLIENT_ID,
        )

    @cached_property
    def email_store(self):
        return SqliteEmailStore(
            page_size=AppConfig.EMAILS_PER_PAGE,
            restricted={AppConfig.NEWS_INBOX: AppConfig.NEWS_SENDERS},
            database_path=AppConfig.LOCAL_EMAIL_STORE,
        )

    @cached_property
    def email_sync(self):
        return AzureSync(
            compression=AppConfig.COMPRESSION,
            account_name=AppConfig.STORAGE_ACCOUNT_NAME,
            account_key=AppConfig.STORAGE_ACCOUNT_KEY,
            email_server_client=self.email_server_client,
            container=AppConfig.STORAGE_CONTAINER,
            provider=AppConfig.STORAGE_PROVIDER,
            serializer=self.serializer,
        )

    @cached_property
    def user_store(self):
        return FlaskLoginUserStore()


def _new_ioc(fqn: str) -> Ioc:
    fqn_parts = fqn.split('.')
    class_name = fqn_parts.pop()
    module_name = '.'.join(fqn_parts)

    module = import_module(module_name)
    cls = getattr(module, class_name)

    return cls()


def create_app(config=AppConfig) -> Flask:
    app = Flask(__name__)
    app.config.from_object(config)

    app.babel = Babel(app)

    app.ioc = _new_ioc(config.IOC)

    cache.init_app(app)
    app.ioc.user_store.init_app(app)
    security.init_app(app, app.ioc.user_store.r, register_form=RegisterForm, login_form=LoginForm)

    app.register_blueprint(mkwvconf, url_prefix='/api/mkwvconf')

    return app

@@ -2096,24 +2096,97 @@
 serStore()%0A%0A
+    @cached_property%0A    def login_form(self):%0A        return LoginForm%0A%0A
 %0Adef _new_io
@@ -2724,22 +2724,31 @@
 in_form=
-L
+app.ioc.l
 ogin
-F
+_f
 orm)%0A%0A  

Enable injection of login form (#243)