import operator
from ocyan.core.fender import config
from django.conf import settings
from ocyan.main.loading import get_ocyan_class

from .constants import (
    COOKIE_TYPES,
    COOKIE_TYPE_FUNCTIONAL,
    COOKIE_TYPE_ANALYTICAL,
    COOKIE_TYPE_SOCIAL,
    COOKIE_TYPE_MARKETING,
    COOKIE_KEY,
    COOKIE_MODIFIERS,
)

parse_cookie = get_ocyan_class("cookie_jar.utils", "parse_cookie")

COOKIE_TYPES_REQUIRING_APPROVAL = (COOKIE_TYPE_SOCIAL, COOKIE_TYPE_MARKETING)

get_required_approvals = operator.itemgetter(*COOKIE_TYPES_REQUIRING_APPROVAL)


class AcceptedIsTrue(object):
    """
    Allows for checks in template if a cookie type was approved

    >>> a = AcceptedIsTrue(False, False)
    >>> a["accepted"]
    True
    >>> a["is_accepted"]
    True
    >>> bool(a)
    True
    >>> b = AcceptedIsTrue(True, False)
    >>> b["accepted"]
    False
    >>> b["is_accepted"]
    False
    >>> bool(b)
    False
    >>> c = AcceptedIsTrue(True, True)
    >>> c["accepted"]
    True
    >>> c["is_accepted"]
    True
    >>> bool(c)
    True
    >>> d = AcceptedIsTrue(False, True)
    >>> d["accepted"]
    True
    >>> d["is_accepted"]
    True
    >>> bool(d)
    True
    """

    def __init__(self, requires_approval, cookie_val):
        self.requires_approval = requires_approval
        self.cookie_val = cookie_val

    def __getitem__(self, name):
        return bool(self)

    def __bool__(self):
        return settings.COOKIE_JAR_ENABLED and (
            not self.requires_approval or self.cookie_val
        )


class CookieContext(dict):
    """
    This object can be accessed in all templates because it is added by
    a context processor. Use it like this::

        // find out if the bar needs display
        {{ cookie_jar.needs_approval }} // do we use any cookies that require approval?
        {{ cookie_jar.needs_display }}  // should we show the cookie bar?

        // find out if certain cookie types can be used
        {% if cookie_jar.analytical.is_allowed %}  // is using analytical cookies allowed?{% endif %}
        {% if cookie_jar.analytical %}  // <-- same as above{% endif %}
        {% if cookie_jar.analytical.accepted %} // <-- also the same we are not fussy{% endif %}

        // find out the settings for the cookie_jar plugin
        {% if cookie_jar.settings.marketing %}
          // omg we are using marketing cookies
        {% endif %}

    The cookie types are: functional, analytical, social and marketing
    """

    def __init__(self, request):
        super().__init__(
            settings=config.get_section("cookie_jar") or {},
            cookie=parse_cookie(request),
            cookie_key=COOKIE_KEY,
            scriptdelay=settings.COOKIE_JAR_SCRIPT_DELAY,
        )

    def is_accepted(self, cookie_type):
        if self["cookie"] is None:
            return False
        return self["cookie"].get(cookie_type)

    @property
    def functional(self):
        return AcceptedIsTrue(
            COOKIE_TYPE_FUNCTIONAL in COOKIE_TYPES_REQUIRING_APPROVAL,
            self.is_accepted(COOKIE_TYPE_FUNCTIONAL),
        )

    @property
    def script_location(self):
        return self["settings"].get("script_location", "footer")

    @property
    def tagmanager(self):
        cookie_type = self["settings"].get(
            "google_tag_manager_cookie_type", COOKIE_TYPE_ANALYTICAL
        )
        return AcceptedIsTrue(
            cookie_type in COOKIE_TYPES_REQUIRING_APPROVAL,
            self.is_accepted(cookie_type),
        )

    @property
    def facebook(self):
        cookie_type = self["settings"].get(
            "facebook_pixel_cookie_type", COOKIE_TYPE_MARKETING
        )
        return AcceptedIsTrue(
            cookie_type in COOKIE_TYPES_REQUIRING_APPROVAL,
            self.is_accepted(cookie_type),
        )

    @property
    def analytical(self):
        return AcceptedIsTrue(
            COOKIE_TYPE_ANALYTICAL in COOKIE_TYPES_REQUIRING_APPROVAL,
            self.is_accepted(COOKIE_TYPE_ANALYTICAL),
        )

    @property
    def social(self):
        return AcceptedIsTrue(
            COOKIE_TYPE_SOCIAL in COOKIE_TYPES_REQUIRING_APPROVAL,
            self.is_accepted(COOKIE_TYPE_SOCIAL),
        )

    @property
    def marketing(self):
        return AcceptedIsTrue(
            COOKIE_TYPE_MARKETING in COOKIE_TYPES_REQUIRING_APPROVAL,
            self.is_accepted(COOKIE_TYPE_MARKETING),
        )

    @property
    def needs_display(self):
        return self.needs_approval and self["cookie"] is None

    @property
    def needs_approval(self):
        return any(get_required_approvals(self["settings"]))

    def _activated_snippet_templates(self, template_path):
        for key, setting in self["settings"].items():
            if (
                key in COOKIE_TYPES or key in COOKIE_MODIFIERS
            ):  # skip cookie type settings
                continue
            if setting:  # only use filled out settings, skip empty
                # not all of the snippets are required to be present
                # so when they are not present for the different settings:
                # we use a default empty.html
                yield [template_path % key, "empty.html"]

    @property
    def activated_snippet_header_templates(self):
        return self._activated_snippet_templates("cookie_jar/snippets/%s/header.html")

    @property
    def activated_snippet_footer_templates(self):
        return self._activated_snippet_templates("cookie_jar/snippets/%s/footer.html")

    @property
    def activated_snippet_basket_addition_templates(self):
        return self._activated_snippet_templates(
            "cookie_jar/snippets/%s/basket/messages/addition.html"
        )

    @property
    def activated_snippet_detail_templates(self):
        return self._activated_snippet_templates(
            "cookie_jar/snippets/%s/catalogue/detail.html"
        )

    @property
    def activated_snippet_browse_templates(self):
        return self._activated_snippet_templates(
            "cookie_jar/snippets/%s/catalogue/browse.html"
        )

    @property
    def activated_snippet_checkout_templates(self):
        return self._activated_snippet_templates(
            "cookie_jar/snippets/%s/checkout/onestep.html"
        )


class NoCookiesContext(CookieContext):
    def __init__(self, request):
        super().__init__(request)
        self["settings"] = {
            "functional": False,
            "analytical": False,
            "social": False,
            "marketing": False,
        }
