import calendar
from datetime import datetime, date, timedelta
from django.db import models
from cms.models import CMSPlugin
from filer.fields.image import FilerImageField
from django.core.urlresolvers import reverse
from django.utils.functional import cached_property
from .mixins import Ordereable

# from membership.models import StripeCustomer
# from utils.models import BillingAddress


class MembershipType(models.Model):

    MEMBERSHIP_TYPES = (
        ('standard', 'Standard'),

    )
    name = models.CharField(choices=MEMBERSHIP_TYPES, max_length=20)
    price = models.FloatField()

    @cached_property
    def days_left(self):
        current_date = date.today()
        _, days_in_month = calendar.monthrange(current_date.year, current_date.month)
        pass_days = current_date.day
        days_left = days_in_month - pass_days + 1
        return days_left

    @cached_property
    def first_month_price(self):
        current_date = date.today()
        _, days_in_month = calendar.monthrange(current_date.year, current_date.month)
        pass_days = current_date.day
        days_left = days_in_month - pass_days + 1
        percentage = days_left / days_in_month
        membership_price = self.price
        final_price = membership_price * percentage
        return final_price

    @cached_property
    def first_month_range(self):
        current_date = date.today()
        _, days_in_month = calendar.monthrange(current_date.year, current_date.month)
        pass_days = current_date.day
        days_left = days_in_month - pass_days
        end_date = current_date + timedelta(days=days_left)
        return current_date, end_date

    @cached_property
    def first_month_formated_range(self):
        start_date, end_date = self.first_month_range
        return "{} - {}".format(datetime.strftime(start_date, "%b, %d %Y"),
                                datetime.strftime(end_date, "%b, %d %Y"))


class Membership(models.Model):
    type = models.ForeignKey(MembershipType)

    @classmethod
    def create(cls, data):
        instance = cls.objects.create(**data)
        return instance


class MembershipOrder(Ordereable, models.Model):
    membership = models.ForeignKey(Membership)

    @classmethod
    def create(cls, data):
        stripe_charge = data.pop('stripe_charge', None)
        instance = cls.objects.create(**data)
        instance.stripe_charge_id = stripe_charge.id
        instance.last4 = stripe_charge.source.last4
        instance.cc_brand = stripe_charge.source.brand
        return instance


class BookingPrice(models.Model):
    price_per_day = models.FloatField()
    special_price_offer = models.FloatField()


class Booking(models.Model):
    start_date = models.DateField()
    end_date = models.DateField()
    price = models.FloatField()
    free_days = models.IntegerField(default=0)

    @classmethod
    def create(cls, data):
        instance = cls.objects.create(**data)
        return instance

    @classmethod
    def get_ramaining_free_days(cls, user):
        # ZERO_DAYS = 0
        # ONE_DAY = 1
        TWO_DAYS = 2

        current_date = datetime.today()
        current_month_bookings = cls.objects.filter(bookingorder__customer__user=user,
                                                    start_date__month=current_date.month)
        free_days = TWO_DAYS - sum(map(lambda x: x.days, current_month_bookings))
        return free_days

        # free_days = ZERO_DAYS if current_month_bookings.count() > 2 else TWO_DAYS
        # if current_month_bookings.count() == 1:
        #     booking = current_month_bookings.get()
        #     booked_days = (booking.end_date - booking.start_date).days
        #     free_days = ONE_DAY if booked_days == 1 else ZERO_DAYS
        #     return free_days

        # free_days = ZERO_DAYS if current_month_bookings.count() > 2 else TWO_DAYS
        # return free_days

    @classmethod
    def booking_price(cls, user, start_date, end_date):
        """
            Calculate the booking price for requested dates
            How it does:
            1. Check if the user has booked the current month
            2. Get how many days user wants to book
            3. Get price per day from BookingPrices instance
            4. Get available free days
            5. Calculate price by  this formula -> (booking_days - free_days) * price_per_day
        """
        booking_prices = BookingPrice.objects.last()
        price_per_day = booking_prices.price_per_day
        booking_days = (end_date - start_date).days

        free_days = cls.get_ramaining_free_days(user)
        final_booking_price = (booking_days - free_days) * price_per_day
        original_booking_price = (booking_days) * price_per_day

        return original_booking_price, final_booking_price, free_days


class BookingOrder(Ordereable, models.Model):
    booking = models.OneToOneField(Booking)


class Supporter(models.Model):
    name = models.CharField(max_length=200)
    description = models.TextField(null=True, blank=True)

    def __str__(self):
        return "%s" % (self.name)

    def get_absolute_url(self):
        return reverse('dgSupporters_view', args=[self.pk])


class DGGallery(models.Model):
    parent = models.ForeignKey('self', blank=True, null=True)
    name = models.CharField(max_length=30)

    def __str__(self):
        return "%s" % (self.name)

    def get_absolute_url(self):
        return reverse('dgGallery_view', args=[self.pk])

    class Meta:
        verbose_name_plural = 'dgGallery'
#
class DGPicture(models.Model):
    gallery = models.ForeignKey(DGGallery)
    image =  FilerImageField(related_name='dg_gallery')
    description = models.CharField(max_length=60)

    def __str__(self):
        return "%s" % (self.image.name)

class DGGalleryPlugin(CMSPlugin):
    dgGallery = models.ForeignKey(DGGallery)

class DGSupportersPlugin(CMSPlugin):
    pass