import importlib

from django.conf.urls.i18n import i18n_patterns
from django.urls import include, path, re_path
from django.utils.text import slugify

from ocyan.core.fender import config
from ocyan.core.plugins import OcyanPluginConfig
from ocyan.core.utils import find_first, merge_dicts

PROJECT_NAME = config.get("django", "name")

try:
    ELASTICSEARCH_SERVER_URLS = importlib.import_module(
        f"{PROJECT_NAME}.json",
    ).ELASTICSEARCH_SERVER_URLS
except (ModuleNotFoundError, AttributeError):
    ELASTICSEARCH_SERVER_URLS = "http://127.0.0.1:9200"

ELASTICSEARCH_OPTIONS = {}
ELASTICSEARCH_USERNAME = config.get("oscar_elasticsearch", "username", None)
ELASTICSEARCH_PASSWORD = config.get("oscar_elasticsearch", "password", None)
ELASTICSEARCH_API_KEY = config.get("oscar_elasticsearch", "api_key", None)
ELASTICSEARCH_VERIFY_CERTS = config.get("oscar_elasticsearch", "verify_certs", None)
ELASTICSEARCH_CA_CERTS = config.get("oscar_elasticsearch", "ca_certs", None)

if ELASTICSEARCH_API_KEY:
    ELASTICSEARCH_OPTIONS["api_key"] = ELASTICSEARCH_API_KEY
elif ELASTICSEARCH_USERNAME and ELASTICSEARCH_PASSWORD:
    ELASTICSEARCH_OPTIONS["basic_auth"] = (
        ELASTICSEARCH_USERNAME,
        ELASTICSEARCH_PASSWORD,
    )

if ELASTICSEARCH_VERIFY_CERTS is not None:
    ELASTICSEARCH_OPTIONS["verify_certs"] = ELASTICSEARCH_VERIFY_CERTS
if ELASTICSEARCH_CA_CERTS:
    ELASTICSEARCH_OPTIONS["ca_certs"] = ELASTICSEARCH_CA_CERTS


WAGTAIL_SETTINGS = {
    "WAGTAIL_SITE_NAME": PROJECT_NAME,
    "WAGTAIL_ENABLE_UPDATE_CHECK": False,
    "WAGTAILIMAGES_EXTENSIONS": ["gif", "jpg", "jpeg", "png", "webp", "svg"],
    "OPEN_EXTERNAL_RICHTEXT_LINKS_IN_NEW_WINDOW": config.get(
        "wagtail", "open_external_richtext_links_in_new_window", False
    ),
    "WAGTAIL_SEARCH_QUERY_OPERATOR": config.get(
        "wagtail", "wagtail_search_query_operator", "or"
    ),
    # this SILENCED_SYSTEM_CHECKS urls.W005 can be removed as soon as the overrides in views.py
    # are nolonger needed.
    "SILENCED_SYSTEM_CHECKS": ["urls.W005"],
    "WAGTAILSEARCH_BACKENDS": {
        "default": {
            "BACKEND": "ocyan.plugin.wagtail.backends.elasticsearch8",
            "URLS": ELASTICSEARCH_SERVER_URLS,
            "INDEX_PREFIX": slugify(PROJECT_NAME),
            "TIMEOUT": 20,
            "OPTIONS": ELASTICSEARCH_OPTIONS,
            # Wagtail provides sensible defaults for analyzers/tokenizers.
            # We only override max_ngram_diff here, which is needed when using
            # ngram filters/tokenizers with a larger (max_gram - min_gram).
            "INDEX_SETTINGS": {"settings": {"index": {"max_ngram_diff": 20}}},
            "ATOMIC_REBUILD": True,
            "AUTO_UPDATE": True,
        }
    },
}

WAGTAIL_TEMPLATE_SETTINGS = {
    "OPTIONS": {
        "context_processors": ["wagtail.contrib.settings.context_processors.settings"]
    }
}


class WagtailConfig(OcyanPluginConfig):
    def contribute_to_settings(self, settings):
        # find django template settings dict
        django_templates = find_first(
            lambda x: x["BACKEND"].endswith("DjangoTemplates"), settings["TEMPLATES"]
        )

        # configure templates
        merge_dicts(django_templates, WAGTAIL_TEMPLATE_SETTINGS, overwrite=True)

        # add the rest of the wagtail settings
        return merge_dicts(settings, WAGTAIL_SETTINGS)

    def contribute_to_urlpatterns(self, urlpatterns):
        if config.i18n_enabled:
            return urlpatterns + i18n_patterns(
                re_path(r"^admin/", include("wagtail.admin.urls")),
                re_path(r"^documents/", include("wagtail.documents.urls")),
                path("pages/", include("ocyan.plugin.wagtail.urls")),
                path(r"", include("wagtail.urls")),
                prefix_default_language=False,
            )

        return urlpatterns + [
            re_path(r"^admin/", include("wagtail.admin.urls")),
            re_path(r"^documents/", include("wagtail.documents.urls")),
            path("pages/", include("ocyan.plugin.wagtail.urls")),
            path(r"", include("wagtail.urls")),
        ]

    def contribute_to_installed_apps(self, installed_apps):
        installed_apps.ocyan.append(
            "ocyan.plugin.wagtail.apps.OcyanPluginWagtailConfig"
        )
        installed_apps.apps.extend(("modelcluster", "taggit"))
        installed_apps.wagtail.extend(
            (
                "ocyan.plugin.wagtail_i18n",
                "wagtail.contrib.forms",
                "wagtail.contrib.redirects",
                "wagtail.contrib.search_promotions",
                "wagtail.embeds",
                "wagtail.sites",
                "wagtail.users",
                "wagtail.snippets",
                "wagtail.documents",
                "ocyan.plugin.wagtail.wagtailimagesapp.DontDeleteImagesWagtailImagesAppConfig",
                "wagtail.search",
                "wagtail.admin",
                "wagtail.contrib.legacy.richtext",
                "wagtail",
                "wagtailmetadata",
                "wagtail.contrib.settings",
            )
        )
        return installed_apps

    def contribute_to_middleware(self, middleware):
        return middleware + [
            "wagtail.contrib.redirects.middleware.RedirectMiddleware",
            "ocyan.plugin.wagtail.middleware.RequestContextMiddleware",
        ]

    def contribute_to_fixtures(self, fixtures):
        fixtures.add("wagtailroot", "wagtail/root")
        fixtures.add("wagtailhome", "wagtail/pages")
        fixtures.add("wagtailsites", "wagtail/sites")
        fixtures.add("wagtailsettings", "wagtail/settings")
        fixtures.add("wagtailimages", "wagtail/images")

        return fixtures

    def contribute_to_i18n_fields(self, fields_dict):
        fields_dict.update(
            {
                "ocyan_plugin_wagtail.ocyansettings.delivery_time_text": True,
                "ocyan_plugin_wagtail.ocyansettings.footer": True,
                "ocyan_plugin_wagtail.ocyansettings.mini_footer": True,
                "ocyan_plugin_wagtail.ocyansettings.header_content": True,
                "ocyan_plugin_wagtail.ocyansettings.promo_header": True,
                "ocyan_plugin_wagtail.ocyansettings.invoice_footer_text": True,
                "ocyan_plugin_wagtail.ocyansettings.seo_title": True,
                "ocyan_plugin_wagtail.ocyansettings.seo_description": True,
            }
        )
        return fields_dict

    def get_smoketest_modules(self):
        return [
            "ocyan.plugin.wagtail.tests.test_screenshots",
        ]

    def get_spooler_modules(self, modules):
        modules.append("ocyan.plugin.wagtail.spooler")
        return modules
