# coding=utf-8
from __future__ import absolute_import, division, print_function, unicode_literals

from django.apps import AppConfig
from django.conf import settings
from django.test.signals import setting_changed

import scout_apm.core
from scout_apm.core.config import scout_config
from scout_apm.django.instruments.huey import ensure_huey_instrumented
from scout_apm.django.instruments.sql import ensure_sql_instrumented
from scout_apm.django.instruments.template import ensure_templates_instrumented


class ScoutApmDjangoConfig(AppConfig):
    name = "scout_apm"
    verbose_name = "Scout Apm (Django)"

    def ready(self):
        self.update_scout_config_from_django_settings()
        setting_changed.connect(self.on_setting_changed)

        # Finish installing the agent. If the agent isn't installed for any
        # reason, return without installing instruments
        installed = scout_apm.core.install()
        if not installed:
            return

        self.install_middleware()

        # Setup Instruments
        ensure_huey_instrumented()
        ensure_sql_instrumented()
        ensure_templates_instrumented()

    def update_scout_config_from_django_settings(self, **kwargs):
        for name in dir(settings):
            self.on_setting_changed(name)

    def on_setting_changed(self, setting, **kwargs):
        cast = None
        if setting == "BASE_DIR":
            scout_name = "application_root"
            cast = str
        elif setting.startswith("SCOUT_"):
            scout_name = setting.replace("SCOUT_", "").lower()
        else:
            return

        try:
            value = getattr(settings, setting)
        except AttributeError:
            # It was removed
            scout_config.unset(scout_name)
        else:
            if cast is not None:
                value = cast(value)
            scout_config.set(**{scout_name: value})

    def install_middleware(self):
        """
        Attempts to insert the ScoutApm middleware as the first middleware
        (first on incoming requests, last on outgoing responses).
        """
        from django.conf import settings

        # If MIDDLEWARE is set, update that, with handling of tuple vs array forms
        if getattr(settings, "MIDDLEWARE", None) is not None:
            timing_middleware = "scout_apm.django.middleware.MiddlewareTimingMiddleware"
            view_middleware = "scout_apm.django.middleware.ViewTimingMiddleware"

            if isinstance(settings.MIDDLEWARE, tuple):
                if timing_middleware not in settings.MIDDLEWARE:
                    settings.MIDDLEWARE = (timing_middleware,) + settings.MIDDLEWARE
                if view_middleware not in settings.MIDDLEWARE:
                    settings.MIDDLEWARE = settings.MIDDLEWARE + (view_middleware,)
            else:
                if timing_middleware not in settings.MIDDLEWARE:
                    settings.MIDDLEWARE.insert(0, timing_middleware)
                if view_middleware not in settings.MIDDLEWARE:
                    settings.MIDDLEWARE.append(view_middleware)

        # Otherwise, we're doing old style middleware, do the same thing with
        # the same handling of tuple vs array forms
        else:
            timing_middleware = (
                "scout_apm.django.middleware.OldStyleMiddlewareTimingMiddleware"
            )
            view_middleware = "scout_apm.django.middleware.OldStyleViewMiddleware"

            if isinstance(settings.MIDDLEWARE_CLASSES, tuple):
                if timing_middleware not in settings.MIDDLEWARE_CLASSES:
                    settings.MIDDLEWARE_CLASSES = (
                        timing_middleware,
                    ) + settings.MIDDLEWARE_CLASSES

                if view_middleware not in settings.MIDDLEWARE_CLASSES:
                    settings.MIDDLEWARE_CLASSES = settings.MIDDLEWARE_CLASSES + (
                        view_middleware,
                    )
            else:
                if timing_middleware not in settings.MIDDLEWARE_CLASSES:
                    settings.MIDDLEWARE_CLASSES.insert(0, timing_middleware)
                if view_middleware not in settings.MIDDLEWARE_CLASSES:
                    settings.MIDDLEWARE_CLASSES.append(view_middleware)