# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from shop.modifiers.base import BaseCartModifier


class ShippingModifier(BaseCartModifier):
    """
    Base class for all shipping modifiers. The purpose of a shipping modifier is to calculate the shipping costs and/or
    prevent its usage, in case products in the cart can not be shipped to the desired destination. The merchant may
    either append a single shipping modifier to the list of ``SHOP_CART_MODIFIERS``, or create a sublist of shipping
    modifier and append this sublist to ``SHOP_CART_MODIFIERS``. The latter is useful to instantiate the same shipping
    modifier multiple times for different shipping carriers using the same interface.

    The merchant must specify at least one shipping modifier. If there is more than one, the merchant shall offer a
    select option during checkout. In django-SHOP, one can use the plugin **Shipping Method Form** to render such a
    select option.

    Each shipping modifier can add a surcharge on the current cart. If weight affects the shipping price, it shall be
    summed up inside the method `add_extra_cart_row` and used to lookup the shipping costs.
    """
    def get_choice(self):
        """
        :returns: A tuple consisting of 'value, label' used by the shipping form dialog to render
        the available shipping choices.
        """
        raise NotImplemented("{} must implement method `get_choice()`.".format(self.__class__))

    def is_active(self, shipping_modifier):
        """
        :returns: ``True`` if this shipping modifier is the actively selected one.
        """
        return shipping_modifier == self.identifier

    def is_disabled(self, cart):
        """
        Hook method to be overridden by the concrete shipping modifier. Shall be used to
        temporarily disable a shipping method, in case the cart does not fulfill certain criteria,
        for instance an undeliverable destination address.

        :returns: ``True`` if this shipping modifier is disabled for the current cart.
        """
        return False

    def update_render_context(self, context):
        """
        Hook to update the rendering context with shipping specific data.
        """
        from shop.models.cart import CartModel

        if 'shipping_modifiers' not in context:
            context['shipping_modifiers'] = {}
        try:
            cart = CartModel.objects.get_from_request(context['request'])
            if self.is_active(cart.extra.get('shipping_modifier')):
                cart.update(context['request'])
                data = cart.extra_rows[self.identifier].data
                data.update(modifier=self.identifier)
                context['shipping_modifiers']['initial_row'] = data
        except (KeyError, CartModel.DoesNotExist):
            pass

    def ship_the_goods(self, delivery):
        """
        Hook to be overridden by the active shipping modifier. It should be used to perform the
        shipping request.
        """
        delivery.shipped_at = timezone.now()


class SelfCollectionModifier(ShippingModifier):
    """
    This modifiers has not influence on the cart final. It can be used,
    to enable the customer to pick up the products in the shop.
    """
    identifier = 'self-collection'

    def get_choice(self):
        return (self.identifier, _("Self-collection"))

    def ship_the_goods(self, delivery):
        if not delivery.shipping_id:
            delivery.shipping_id = str(delivery.id)
        super(SelfCollectionModifier, self).ship_the_goods(delivery)
