#!/usr/bin/env python
""" Django models for cart """
# -*- coding: utf-8 -*-
from decimal import Decimal
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User

from .managers import CartManager, CartItemManager
from pbp_core.utils import temp_code, pbp_converter


class Cart(models.Model):
    """ Shopping cart """

    # basically session_key
    cart_id = models.CharField(max_length=50, db_index=True)
    owner = models.ForeignKey(User, related_name="cart", null=True, blank=True)
    creation_date = models.DateTimeField(auto_now_add=True)
    last_update = models.DateTimeField(auto_now_add=True, auto_now=True)
    checked_out = models.BooleanField(default=False)

    objects = CartManager()

    class Meta:
        """ Django model meta class """

        verbose_name = _("Cart")
        verbose_name_plural = _("Carts")
        ordering = ("-creation_date",)

    def __unicode__(self):
        """ unicode name of model """
        return u"Cart: {0}".format(unicode(self.cart_id))

    @property
    def has_items(self):
        """ is the cart empty?"""
        return self.item_count > 0

    @property
    def cart_items(self):
        """ return all cart items"""
        return self.items.all()

    @property
    def item_count(self):
        """ number of items """
        return self.items.count()

    @property
    def cart_shipping_total(self):
        """ Total shipping cost"""
        price = Decimal(0.0)
        for item in self.cart_items:
            price = price + item.total_shipping_cost
        return price

    @property
    def cart_subtotal(self):
        """ cart subtotal"""
        price = Decimal(0.0)
        for item in self.cart_items:
            price = price + item.total_price
        return price

    @property
    def cart_total(self):
        """ total cart cost"""
        return self.cart_subtotal + self.cart_shipping_total

    @property
    def purchase_description(self):
        """ the purchase description for carts """
        description = ""
        for item in self.cart_items:
            description = description + "<br>" + item.by_line
        return description

    @property
    def buyer_id(self):
        """ the buyer for the person who created the cart"""
        if self.owner:
            return self.owner.pk
        return None


class CartItemGiftDetail(models.Model):
    """ Cart Item gift detail """

    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    company = models.CharField(max_length=30, blank=True, null=True)
    address1 = models.CharField(max_length=30)
    address2 = models.CharField(max_length=30, blank=True, null=True)
    city = models.CharField(max_length=30)
    region = models.CharField(max_length=30)
    phone = models.CharField(max_length=30)
    country = models.CharField(max_length=30)
    country_other = models.CharField(max_length=30)
    postal_code = models.CharField(max_length=30)
    plus_four = models.CharField(max_length=4)
    email = models.CharField(max_length=30)
    bill_on_renewal = models.CharField(max_length=10)
    gift_card_delivery = models.CharField(max_length=10)
    message = models.CharField(max_length=72, null=True, blank=True)


class CartItem(models.Model):
    """ Cart items """

    cart = models.ForeignKey(Cart, verbose_name=_("cart"), related_name="items")
    quantity = models.PositiveIntegerField(verbose_name=_("quantity"))

    # need a unique value we can reference when editing
    # that won't be easy to spoof
    cart_token = models.CharField(_("Cart Token"), max_length=255, db_index=True)

    # product as generic relation
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    gift_detail = models.OneToOneField(CartItemGiftDetail, null=True, blank=True)
    account_number = models.CharField(max_length=7, null=True, blank=True)

    class Meta:
        """ Model meta class"""

        verbose_name = _("item")
        verbose_name_plural = _("items")
        ordering = ("cart",)

    objects = CartItemManager()

    def __unicode__(self):
        """ unicode repr of class """
        return "Item in cart: " + unicode(self.product)

    def save(self, *args, **kwargs):
        """ We need to set the cart_token to make sure it is unique """

        # This check should be skipped since cart_token is required.
        # keeping it in for now to clean up stale data
        if not self.cart_token:
            if not self.pk:
                self.cart_token = temp_code()
                super(CartItem, self).save(*args, **kwargs)
                # saving with force_insert twice leads to sad
                kwargs.pop("force_insert", None)
            encode_value = pbp_converter.encode(str(self.pk))
            self.cart_token = "P%s" % encode_value

        super(CartItem, self).save(*args, **kwargs)

    @property
    def is_gift(self):
        """ is this a gift? """
        if self.gift_detail:
            return True
        return False

    @property
    def image(self):
        """ get the image """
        return self.product.image

    @property
    def unit_price(self):
        """ unit price """
        return self.product.price

    @property
    def name(self):
        """ name """
        return self.product.title

    @property
    def description(self):
        """ description """
        return self.product.description

    @property
    def by_line(self):
        """ get the byline"""
        return "{0} {1}".format(self.name, self.description)

    @property
    def sku(self):
        """ get the sku """
        return self.product.sku

    @property
    def total_shipping_cost(self):
        """ Shipping costs. If there is just one item take the shipping_cost
        from the product, if there is more then one, for each item after the
        first one, the shipping cost is shipping_cost_multiple for each item
        total them together to get the total shipping cost
        """
        initial_cost = self.product.shipping_cost
        extra_item_costs = self.product.shipping_cost_multiple
        if self.quantity == 0:
            return 0.0
        if self.quantity == 1:
            return initial_cost
        elif self.quantity > 1:
            return initial_cost + ((self.quantity - 1) * extra_item_costs)

    @property
    def total_price(self):
        """ total price """
        return self.quantity * self.unit_price

    @property
    def sub_total(self):
        """ price including shipping """
        return self.total_price + self.total_shipping_cost

    def get_product(self):
        """ get the product """
        return self.content_type.get_object_for_this_type(id=self.object_id)

    def set_product(self, product):
        """ set the product """
        self.content_type = ContentType.objects.get_for_model(type(product))
        self.object_id = product.pk

    product = property(get_product, set_product)
