# -*- coding: utf-8 -*-
from django.contrib import messages
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.urls import reverse
from django.utils.translation import gettext as _
from django.views.generic import ListView

from oscar.core.loading import get_model
from oscar.core.utils import redirect_to_referrer
from oscar.templatetags.currency_filters import currency as C

from .constants import (
    COMPARISION_ADDED_MESSAGE,
    COMPARISION_REMOVED_MESSAGE,
    COMPARISION_SESSION_KEY,
)

Product = get_model("catalogue", "Product")
ProductAttributeValue = get_model("catalogue", "ProductAttributeValue")


def start_comparison(request):
    product_ids = request.session.get(COMPARISION_SESSION_KEY, [])
    products_for_comparison_url = (
        (reverse("compare:products", kwargs={"products": product_ids}))
        if product_ids
        else "#"
    )
    return HttpResponseRedirect(products_for_comparison_url)


def add_product(request, pk):
    product = get_object_or_404(Product, pk=pk)
    ids = request.session.get(COMPARISION_SESSION_KEY, [])
    ids.append(product.id)
    request.session[COMPARISION_SESSION_KEY] = ids
    messages.success(
        request,
        COMPARISION_ADDED_MESSAGE % {"link": reverse("compare:start_comparison")},
        extra_tags="safe",
    )
    return redirect_to_referrer(request, product.get_absolute_url())


def remove_product(request, pk):
    product = get_object_or_404(Product, pk=pk)
    ids = request.session.get(COMPARISION_SESSION_KEY, [])
    ids.remove(product.id)
    request.session[COMPARISION_SESSION_KEY] = ids
    messages.info(request, COMPARISION_REMOVED_MESSAGE)
    return redirect_to_referrer(request, product.get_absolute_url())


class CompareProducts(ListView):
    template_name = "compare/products.html"
    model = Product
    context_object_name = "products"

    def get_queryset(self):
        return Product.objects.filter(
            id__in=self.kwargs.get("products")
        ).prefetch_related("attribute_values")

    def get_context_data(self, *args, **kwargs):  # pylint: disable=W0221
        context = super().get_context_data(*args, **kwargs)
        products = context[self.context_object_name]
        request = self.request
        strategy = request.strategy

        attributes = {}
        incl_tax = []
        excl_tax = []
        tax = []

        for product in products:
            attributes.update(
                {av.attribute: [] for av in product.get_attribute_values()}
            )

        for product in products:
            if product.is_parent:
                session = strategy.fetch_for_parent(product)
            else:
                session = strategy.fetch_for_product(product)

            currency = session.price.currency
            price_exists = session.price.exists

            if price_exists:
                incl_tax.append(C(session.price.incl_tax, currency))
                excl_tax.append(C(session.price.excl_tax, currency))
                tax.append(C(session.price.tax, currency))
            else:
                incl_tax.append(None)
                excl_tax.append(None)
                tax.append(None)

            product_avs = product.get_attribute_values()

            for attribute, values in attributes.items():
                try:
                    value = product_avs.get(attribute=attribute).value_as_html
                except ProductAttributeValue.DoesNotExist:
                    value = None

                values.append(value)

        context["attributes"] = self.add_price_attributes(
            attributes, incl_tax, excl_tax, tax
        )

        return context

    def add_price_attributes(self, attributes, incl_tax, excl_tax, tax):
        price_attributes = {
            _("Price (incl. tax)"): incl_tax,
            _("Price (excl. tax)"): excl_tax,
            _("Tax"): tax,
        }
        price_attributes.update(attributes)

        return price_attributes


def compare_products(request, products):
    return CompareProducts.as_view()(request, products=products)
