from decimal import Decimal

from django.contrib.localflavor.us.us_states import STATE_CHOICES
from django.db import models
from django.contrib.auth.models import User
from django_countries.countries import COUNTRIES

from billing.models import GCNewOrderNotification, AmazonFPSResponse
from catalog.models import Item
from pbp_core.models import TimeStampedModel

from . import constants
from . import managers


class BaseOrderInfo(TimeStampedModel):
    """ base class for storing customer order information """

    class Meta:
        abstract = True

    # contact info
    email = models.EmailField(max_length=50, null=True, blank=True)
    phone = models.CharField(max_length=20, null=True, blank=True)

    # shipping information
    shipping_name = models.CharField(max_length=50, null=True, blank=True)
    shipping_address_1 = models.CharField(max_length=50, null=True, blank=True)
    shipping_address_2 = models.CharField(max_length=50, null=True, blank=True)
    shipping_city = models.CharField(max_length=50, null=True, blank=True)
    shipping_state = models.CharField(max_length=2, null=True, blank=True)
    shipping_country = models.CharField(max_length=50, null=True, blank=True)
    shipping_zip = models.CharField(max_length=10, null=True, blank=True)

    # billing information
    billing_name = models.CharField(max_length=50, null=True, blank=True)
    billing_address_1 = models.CharField(max_length=50, null=True, blank=True)
    billing_address_2 = models.CharField(max_length=50, null=True, blank=True)
    billing_city = models.CharField(max_length=50, null=True, blank=True)
    billing_state = models.CharField(max_length=2, null=True, blank=True)
    billing_country = models.CharField(max_length=50, null=True, blank=True)
    billing_zip = models.CharField(max_length=10, null=True, blank=True)


class Order(BaseOrderInfo):
    """ model class for storing a customer order instance """

    # each individual status
    INIT = 0
    SUBMITTED = 1
    PROCESSED = 2
    SHIPPED = 3
    CANCELLED = 4
    # set of possible order statuses
    ORDER_STATUSES = (
        (INIT, "Initialized"),
        (SUBMITTED, "Submitted"),
        (PROCESSED, "Processed"),
        (SHIPPED, "Shipped"),
        (CANCELLED, "Cancelled"),
    )

    # order info
    date = models.DateTimeField(auto_now_add=True)
    status = models.IntegerField(choices=ORDER_STATUSES, default=INIT)
    ip_address = models.IPAddressField(null=True, blank=True)
    last_updated = models.DateTimeField(auto_now=True)
    user = models.ForeignKey(User, null=True, blank=True)
    transaction_id = models.CharField(max_length=20, null=True, blank=True)
    cart_id = models.CharField(max_length=50, null=True, blank=True)

    objects = managers.OrderManager()

    def __unicode__(self):
        return u"Order #" + str(self.id)

    @property
    def get_status(self):
        for enum, value in self.ORDER_STATUSES:
            if self.status == enum:
                return value

    @property
    def has_items(self):
        return self.item_count > 0

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

    @property
    def order_items(self):
        return self.items.all()

    @property
    def subscription_items(self):
        """ return only the subscriptions """
        for item in self.order_items:
            if item.is_subscription:
                yield item

    @property
    def subtotal(self):
        total = Decimal("0.00")
        for item in self.order_items:
            total += item.total
        return total

    @property
    def shipping_total(self):
        ship_cost = Decimal(0.0)
        for item in self.order_items:
            ship_cost = ship_cost + item.shipping_cost
        return ship_cost

    @property
    def total(self):
        return self.subtotal + self.shipping_total

    @models.permalink
    def get_absolute_url(self):
        return "view_order_detail", (), {"order_number": self.pk}

    def delete_items(self):
        """ delete all orderItems for this order """
        OrderItem.objects.filter(order=self).delete()


class OrderPayment(TimeStampedModel):
    order = models.OneToOneField(Order)
    amazon_payment = models.ForeignKey(
        AmazonFPSResponse, related_name="order_payment", blank=True, null=True
    )
    google_payment = models.ForeignKey(
        GCNewOrderNotification, related_name="order_payment", blank=True, null=True
    )

    @property
    def is_amazon(self):
        if self.amazon_payment:
            return True
        return False

    @property
    def is_google(self):
        if self.google_payment:
            return True
        return False

    @property
    def shipping_state(self):
        if self.is_google:
            return self.google_payment.fulfillment_order_state
        return "N/A"

    @property
    def payment_state(self):
        if self.is_google:
            return self.google_payment.financial_order_state
        return "N/A"


class OrderItemGiftDetail(TimeStampedModel):

    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, choices=STATE_CHOICES)
    phone = models.CharField(max_length=30)
    country = models.CharField(max_length=30, choices=COUNTRIES)
    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, choices=constants.BILL_CHOICES, default=constants.CHOOSE
    )
    gift_card_delivery = models.CharField(
        max_length=10,
        choices=constants.GIFT_CARD_DELIVERY_CHOICES,
        default=constants.GIFT_CARD_NONE,
    )
    message = models.CharField(max_length=72, null=True, blank=True)


class OrderItem(TimeStampedModel):
    """ store each Product instance purchased in each order """

    product = models.ForeignKey(Item)
    quantity = models.IntegerField(default=1)
    price = models.DecimalField(max_digits=9, decimal_places=2)
    order = models.ForeignKey(Order, related_name="items")
    gift_detail = models.OneToOneField(OrderItemGiftDetail, null=True, blank=True)
    account_number = models.CharField(max_length=7, null=True, blank=True)

    @property
    def is_gift(self):
        if self.gift_detail:
            return True
        return False

    @property
    def is_subscription(self):
        if self.product.is_subscription:
            return True
        return False

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

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

    @property
    def long_description(self):
        return self.product.long_description

    @property
    def sku(self):
        return self.product.sku

    def __unicode__(self):
        return self.product.title + " (" + self.product.sku + ")"

    @property
    def 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

        if self.quantity == 0:
            return 0.0
        if self.quantity == 1:
            return initial_cost
        elif self.quantity > 1:
            return initial_cost + (
                (self.quantity - 1) * self.product.shipping_cost_multiple
            )

    @property
    def total_plus_shipping(self):
        return self.total + self.shipping_cost
