from django.db import models
from datetime import datetime,date,time

from django.template.response import SimpleTemplateResponse
from django.template import loader, Context

from django.utils.safestring import SafeUnicode

from modules.core.encryption import EncryptedCharField

from modules.notifications.models import *
from modules.blocks.models import *
from modules.members.models import Receipt

from signals import *

class Meeting(models.Model):

    name                = models.CharField(max_length=100)
    slug                = models.SlugField(max_length=120,unique=True)
    description         = models.TextField()
    start_date          = models.DateField(help_text='Date to start taking bookings from')
    end_date            = models.DateField(help_text='Last date bookings can be made')
    link_to_agenda      = models.CharField(max_length=200,blank=True,null=True)
    link_to_agenda_file = models.FileField(upload_to='meetings',blank=True,null=True)

    #booking
    limit_booking_to_member_types = models.ManyToManyField('members.MemberType',blank=True)

    enabled             = models.BooleanField(default=False)
    limit_number_of_bookings = models.IntegerField(blank=True,null=True,verbose_name='Limit number of bookings?',help_text='Enter the number of bookings allowed to be made to this meeting - leave blank for unlimited')

    confirmation_message = models.TextField(blank=True,null=True,verbose_name='Content for confirmation email')
    receipt_message = models.TextField(blank=True,null=True,verbose_name='Cancellation text for receipt')

    def __unicode__(self):
        return self.name

    def get_resources(self):
        resources = MeetingResource.objects.filter(meeting=self)
        return resources

    def get_sessions(self):
        sessions = MeetingSession.objects.filter(meeting=self)
        return sessions

    def get_booking_types(self):
        booking_types = MeetingBookingType.objects.filter(meeting=self)
        return booking_types

    def get_bookings(self):
        bookings = MeetingBooking.objects.filter(meeting=self)
        return bookings

    def get_complete_bookings(self):
        bookings = MeetingBooking.objects.filter(meeting=self,complete=True).exclude(status='cancelled').exclude(status='rejected')
        return bookings

    def get_social_events(self):
        social_events = MeetingSocialEvent.objects.filter(meeting=self)
        return social_events

    def get_days(self):
        days = MeetingDay.objects.filter(meeting=self)
        return days

    def get_approved_delegates(self):
        bookings = MeetingBooking.objects.filter(meeting=self,registrant_type='delegate',status='approved')
        return bookings

    def get_approved_members(self):
        bookings = MeetingBooking.objects.filter(meeting=self,registrant_type='member',status='approved')
        return bookings


class MeetingSessionCategory(models.Model):

    name = models.CharField(max_length=200)
    order = models.IntegerField()
    meeting = models.ForeignKey('Meeting')
    only_one = models.BooleanField(default=False,verbose_name='Limit session so that only one can be booked')

    def __unicode__(self):
        return self.name

    def get_sessions(self):
        meeting_sessions = MeetingSession.objects.filter(session_category=self)
        return meeting_sessions

class MeetingSession(models.Model):

    name = models.CharField(max_length=100)
    description = models.TextField()
    order = models.IntegerField()
    meeting = models.ForeignKey('Meeting')
    session_category = models.ForeignKey('MeetingSessionCategory')
    quantity_available = models.IntegerField()
    bookable = models.BooleanField(default=True)
    cost   = models.FloatField(default=0,verbose_name='Price (GBP)')

    def __unicode__(self):
        return self.name

    def get_bookings(self):

        session_bookings = MeetingSessionBooking.objects.filter(session=self,waiting_list=False,meeting_booking__complete=True)
        return session_bookings

    def get_approved_bookings(self):

        session_bookings = MeetingSessionBooking.objects.filter(session=self,meeting_booking__status='approved')
        return session_bookings

    def get_quantity_remaining(self):

        session_bookings = self.get_bookings()
        count = session_bookings.count()
        remaining = self.quantity_available - count

        return remaining

class MeetingResource(models.Model):

    name = models.CharField(max_length=150)
    meeting = models.ForeignKey(Meeting)
    resource = models.ForeignKey('resources.Resource')
    order = models.IntegerField()

    def __unicode__(self):
        return self.name

class MeetingBookingType(models.Model):

    meeting = models.ForeignKey(Meeting)
    name = models.CharField(max_length=200)
    cost = models.FloatField(default=0,verbose_name='Cost (GBP)')
    early_bird_date = models.DateField(blank=True,null=True, help_text='Last date which early bird rate can be purchased.')
    early_bird_cost = models.FloatField(blank=True,null=True,verbose_name='Early Bird Cost (GBP)')
    text = models.TextField(help_text='Text that shows when this option is selected.',blank=True,null=True)
    order = models.IntegerField()
    meeting_days_generate = models.BooleanField(default=False,verbose_name='Show Day options for this meeting booking')
    enabled = models.BooleanField(default=True)

    limit_to_member_types = models.ManyToManyField('members.MemberType',blank=True,help_text='Leave blank to allow non-members to choose this option.')
    guests_only = models.BooleanField(default=False,help_text='Tick to limit booking to non-members only')

    def __unicode__(self):
        if self.cost:
            return SafeUnicode("%s -  (&pound;%0.2f)" % (self.name,self.get_cost()))
        else:
            return "%s" % self.name

    def is_earlybird(self,bdate=False):

        if self.early_bird_cost and self.early_bird_date:
            if not bdate :
                bdate = date.today()
            if bdate <= self.early_bird_date:
                return True

        return False

    def get_cost(self,bdate=False):
        if self.early_bird_cost and self.early_bird_date:
            if not bdate :
                bdate = date.today()

            if bdate <= self.early_bird_date:
                cost = self.early_bird_cost
            else:
                cost = self.cost
        else:
            cost = self.cost

        return cost

    def get_approved_bookings(self):
        meeting_bookings = MeetingBooking.objects.filter(type=self,status='approved')
        return meeting_bookings


    class Meta:
        ordering = ['meeting','order']


class MeetingDay(models.Model):

    meeting             = models.ForeignKey(Meeting)
    name                = models.CharField(max_length=100)
    order               = models.IntegerField()
    cost                = models.FloatField(verbose_name='Cost (GBP)')
    cost_member         = models.FloatField(blank=True,null=True,verbose_name='Cost for members (GBP)')
    early_bird_date     = models.DateField(blank=True,null=True,help_text='Last date which early bird rate can be purchased.')
    early_bird_cost     = models.FloatField(blank=True,null=True, verbose_name='Early Bird Cost (GBP)')
    early_bird_member_cost = models.FloatField(blank=True,null=True, verbose_name='Early Bird Member Cost (GBP)')

    def __unicode__(self):
        return "%s %s" % (self.name,self.meeting)


    def get_cost(self,bdate=False):
        if self.early_bird_cost and self.early_bird_date:
            if not bdate :
                bdate = date.today()

            if bdate <= self.early_bird_date:
                cost = self.early_bird_cost
            else:
                if self.cost_eur:
                    cost = self.cost_eur
                else:
                    cost = self.cost
        else:
            cost = self.cost

        return cost

    def get_member_cost(self,bdate=False):
        if self.early_bird_cost and self.early_bird_date:
            if not bdate :
                bdate = date.today()

            if bdate <= self.early_bird_date:
                if self.early_bird_member_cost:
                    cost = self.early_bird_member_cost
                else:
                    cost = self.early_bird_cost
            else:
                if self.cost_member:
                    cost = self.cost_member
                else:
                    cost = self.cost
        else:
            if self.cost_member:
                cost = self.cost_member
            else:
                cost = self.cost

        return cost


class MeetingSocialEvent(models.Model):

    meeting         = models.ForeignKey(Meeting)
    name            = models.CharField(max_length=100)
    max_quantity    = models.IntegerField(verbose_name='Max Quantity Per Booking')
    order           = models.IntegerField()
    cost            = models.FloatField(verbose_name='Cost (GBP)')
    enabled         = models.BooleanField(default=False)

    day_bookings_only = models.BooleanField(default=False)

    def __unicode__(self):
        return "%s %s" % (self.name,self.meeting)

    def get_approved_bookings(self):
        social_event_bookings = MeetingSocialEventBooking.objects.filter(social_event=self,meeting_booking__status='approved')
        return social_event_bookings

class MeetingBooking(models.Model):

    STATUS_CHOICES = (
        (u'pending','Pending'),
        (u'approved','Approved'),
        (u'rejected','Rejected'),
    )

    TITLE_CHOICES = (
        (u'Mr',u'Mr'),
        (u'Mrs',u'Mrs'),
        (u'Miss',u'Miss'),
        (u'Ms',u'Ms'),
        (u'Doctor',u'Doctor'),
        (u'Professor',u'Professor'),
    )

    TYPE_CHOICES = (
        (u'member',u'Member'),
        (u'delegate',u'Delegate'),
    )

    meeting = models.ForeignKey(Meeting)

    registrant_type = models.CharField(max_length=100,choices=TYPE_CHOICES,default='delegate')
    member = models.ForeignKey('members.Member',blank=True,null=True)
    user_registered = models.BooleanField(default=False)

    title = models.CharField(max_length=20,choices=TITLE_CHOICES)
    given_name = models.CharField(max_length=100,verbose_name='First Name')
    surname = models.CharField(max_length=100)
    email_address = models.CharField(max_length=200)
    membership_number = models.IntegerField(blank=True,null=True)

    institution = models.CharField(max_length=200,blank=True,null=True)
    job_title = models.CharField(max_length=200,blank=True,null=True)
    trust = models.CharField(max_length=200,blank=True,null=True)
    hospital = models.CharField(max_length=200,blank=True,null=True)

    address_1 = models.CharField(max_length=200,blank=True,null=True)
    address_2 = models.CharField(max_length=200,blank=True,null=True)
    town = models.CharField(max_length=200,blank=True,null=True)
    county = models.CharField(max_length=200,blank=True,null=True)
    country = models.ForeignKey('members.Country',related_name='booking_country',blank=True,null=True)
    postcode = EncryptedCharField(max_length=20,blank=True,null=True)
    telephone = models.CharField(max_length=40,blank=True,null=True,verbose_name='Phone Number')

    requirements = models.TextField(blank=True,null=True,help_text='Please complete this box if you have any special requirements for your booking, for example dietary requirements or health requirements.')

    price_paid = models.CharField(max_length=200,default=0)
    payment_method = models.CharField(max_length=200,blank=True,null=True)

    type = models.ForeignKey(MeetingBookingType,blank=True,null=True, on_delete=models.SET_NULL)
    type_name = models.CharField(max_length=200,blank=True,null=True)
    type_price = models.FloatField(default=0,blank=True,null=True)

    time = models.DateTimeField(auto_now_add=True)
    status = models.CharField(max_length=200,choices=STATUS_CHOICES,default='pending')
    invoiced = models.BooleanField(default=False)
    paid = models.BooleanField(default=False)
    complete = models.BooleanField(default=False)
    unique_key = models.CharField(max_length=100,blank=True,null=True)

    notes = models.TextField(blank=True,null=True)

    def __unicode__(self):
        return """%s %s - %s""" % (self.given_name, self.surname, self.meeting)

    def get_membership_number(self):
        if self.member:
            return self.member.membership_number
        else:
            return ''

    def get_total(self):

        if self.get_meeting_day_bookings():
            meeting_day_bookings = self.get_meeting_day_bookings()
            base = 0
            for meeting_day_booking in meeting_day_bookings:
                base = base + meeting_day_booking.price_paid

        else:
            base = self.type_price

        session_bookings = self.get_session_bookings()
        for session_booking in session_bookings:
            price_paid = session_booking.price_paid
            base = base + session_booking.price_paid

        social_events = self.get_social_events()

        for social_event in social_events:
            price_paid = social_event.price_paid * social_event.quantity
            base = base + price_paid

        return base

    def get_amount_outstanding(self):
        if not self.paid:
            outstanding = self.get_total()
        else:
            outstanding = '0'

        return outstanding

    def get_session_bookings(self):
        session_bookings = MeetingSessionBooking.objects.filter(meeting_booking=self).order_by('session__session_category__order','session__order')
        return session_bookings

    def get_meeting_day_bookings(self):
        meeting_day_bookings = MeetingDayBooking.objects.filter(meeting_booking=self)
        return meeting_day_bookings

    def get_social_events(self):

        social_events = MeetingSocialEventBooking.objects.filter(meeting_booking=self)
        return social_events

    def get_invoice(self):

        try:
            invoice = MeetingBookingInvoice.objects.get(meeting_booking=self)
            return invoice
        except:
            return False

    def get_receipt(self):

        try:
            receipt = Receipt.objects.get(meeting_booking=self)
            return receipt
        except:
            return False

    def display_booking(self,show_invoice=True):

        try:
            invoice = MeetingBookingInvoice.objects.get(meeting_booking=self)
        except:
            invoice = False

        t = loader.get_template('admin/meeting_booking/bookings/booking-details.html')
        c = Context({ 'meeting_booking': self,'show_invoice':show_invoice,'meeting_booking_invoice':invoice})
        rendered = t.render(c)

        return rendered

    def display_booking_email(self):

        try:
            invoice = MeetingBookingInvoice.objects.get(meeting_booking=self)
        except:
            invoice = False

        t = loader.get_template('admin/meeting_booking/bookings/email-details.html')
        c = Context({ 'meeting_booking': self,'meeting_booking_invoice':invoice})
        rendered = t.render(c)

        return rendered

class MeetingBookingInvoice(models.Model):

    meeting_booking = models.ForeignKey(MeetingBooking)
    organisation_name = models.CharField(max_length=200)

    address_1 = models.CharField(max_length=200)
    address_2 = models.CharField(max_length=200,blank=True,null=True)
    address_3 = models.CharField(max_length=200,blank=True,null=True)
    town = models.CharField(max_length=200)
    country = models.ForeignKey('members.Country',related_name='invoice_country')
    postcode = models.CharField(max_length=20)

    po_number = models.CharField(max_length=100,verbose_name='Purchase Order Number / Contact Name')
    email_address = models.CharField(max_length=100)
    telephone = models.CharField(max_length=20)

    def __unicode__(self):
        return "%s Invoice" % (self.meeting_booking)

class MeetingSessionBooking(models.Model):

    meeting_booking = models.ForeignKey(MeetingBooking)
    session = models.ForeignKey(MeetingSession,blank=True,null=True,on_delete=models.SET_NULL)
    session_name = models.CharField(max_length=200)
    waiting_list = models.BooleanField(default=False)
    price_paid = models.FloatField(default=0)

    def __unicode__(self):
        return """%s - %s """ % (self.meeting_booking,self.session)


class MeetingSocialEventBooking(models.Model):

    meeting_booking     = models.ForeignKey(MeetingBooking)
    social_event        = models.ForeignKey(MeetingSocialEvent,blank=True,null=True,on_delete=models.SET_NULL)
    social_event_name   = models.CharField(max_length=100)
    quantity            = models.IntegerField()
    price_paid          = models.FloatField()

    def __unicode__(self):
        return """%s - %s """ % (self.meeting_booking,self.social_event_name)

class MeetingDayBooking(models.Model):

    meeting_booking     = models.ForeignKey(MeetingBooking)
    meeting_day         = models.ForeignKey(MeetingDay,blank=True,null=True,on_delete=models.SET_NULL)
    meeting_day_name    = models.CharField(max_length=100)
    price_paid          = models.FloatField()

    def __unicode__(self):
        return """%s - %s """ % (self.meeting_booking,self.meeting_day_name)

def meeting_booking_confirmation_handler(sender,**kwargs):

    meeting_booking = kwargs['meeting_booking']
    receipt         = kwargs['receipt']

    email_address = meeting_booking.email_address

    #useremail
    try:
        template = EmailTemplate.objects.get(key="meeting_booking_confirmation")
        invoice_text = ''

        message = template.content % (meeting_booking.meeting.confirmation_message,meeting_booking.display_booking_email())
        subject  = template.subject

        if receipt:
            send_mail(template.key,subject, message, template.from_address.email_address, email_address,False,[receipt.file])
        else:
            send_mail(template.key,subject, message, template.from_address.email_address, email_address)

    except Exception, e:
        raise e

    #admin email
    try:
        template = EmailTemplate.objects.get(key="meeting_booking_admin_confirmation")
        message = template.content % (meeting_booking.meeting.name,meeting_booking.display_booking(),settings.URL,reverse('admin_meeting_booking_bookings',args=[meeting_booking.meeting.id]),settings.URL,reverse('admin_meeting_booking_bookings',args=[meeting_booking.meeting.id]))
        subject  = template.subject

        send_mail(template.key,subject, message, template.from_address.email_address, template.get_to_addresses())
    except Exception, e:
        raise e

meeting_booking_confirmation_email.connect(meeting_booking_confirmation_handler, dispatch_uid="meeting_booking_confirmation")


def meeting_booking_invoice_confirmation_handler(sender,**kwargs):

    #Meeting Booking Email

    request         = kwargs['request']
    meeting_booking = kwargs['meeting_booking']

    email_address = meeting_booking.email_address

    #member email
    try:
        template = EmailTemplate.objects.get(key="meeting_booking_confirmation")

        message = template.content % (meeting_booking.meeting.confirmation_message,meeting_booking.display_booking_email())
        subject  = template.subject

        send_mail(template.key,subject, message, template.from_address.email_address, email_address)
    except Exception, e:
        raise e

    #Admin email
    try:
        template = EmailTemplate.objects.get(key="meeting_booking_invoice_admin_confirmation")
        message = template.content % (meeting_booking.meeting.name,meeting_booking.display_booking(),settings.URL,reverse('admin_meeting_booking_bookings',args=[meeting_booking.meeting.id]),settings.URL,reverse('admin_meeting_booking_bookings',args=[meeting_booking.meeting.id]))
        subject  = template.subject

        send_mail(template.key,subject, message, template.from_address.email_address,template.get_to_addresses())
    except Exception, e:
        raise e

meeting_booking_invoice_email.connect(meeting_booking_invoice_confirmation_handler, dispatch_uid="meeting_booking_invoice_confirmation")


def meeting_booking_invoice_paid_handler(sender,**kwargs):

    request = kwargs["request"]
    meeting_booking = kwargs["meeting_booking"]
    receipt = kwargs["receipt"]

    email_address = meeting_booking.email_address

    try:
        template = EmailTemplate.objects.get(key="meeting_booking_invoice_paid")

        message = template.content % (meeting_booking.meeting)
        subject  = template.subject

        if receipt:
            send_mail(template.key,subject, message, template.from_address.email_address, email_address,False,[receipt.file])
        else:
            send_mail(template.key,subject, message, template.from_address.email_address, email_address)

    except Exception, e:
        raise e

meeting_booking_invoice_paid.connect(meeting_booking_invoice_paid_handler,dispatch_uid="meeting_booking_invoice_paid")


def meeting_booking_approved_handler(sender,**kwargs):

    request         = kwargs['request']
    meeting_booking = kwargs['meeting_booking']

    email_address = meeting_booking.email_address

    if email_address:
        #User email
        try:
            template = EmailTemplate.objects.get(key="meeting_booking_approved")
            message = template.content % (meeting_booking.meeting.name,meeting_booking.display_booking())
            subject  = template.subject

            send_mail(template.key,subject, message, template.from_address.email_address,email_address)
        except Exception, e:
            raise e

meeting_booking_approved.connect(meeting_booking_approved_handler,dispatch_uid="meeting_booking_approved")

def meeting_booking_approved_account_handler(sender,**kwargs):

    request         = kwargs['request']
    meeting_booking = kwargs['meeting_booking']

    if meeting_booking.delegate and meeting_booking.user_registered:
        try:
            template = EmailTemplate.objects.get(key="meeting_booking_delegate_registered")
            message = template.content % (meeting_booking.meeting.name,meeting_booking.delegate.user.email,meeting_booking.delegate.raw_password)
            subject = template.subject

            send_mail(template.key,subject, message,template.from_address.email_address,meeting_booking.delegate.user.email)

        except Exception, e:
            raise e

meeting_booking_approved_account.connect(meeting_booking_approved_account_handler,dispatch_uid="meeting_booking_approved_account")
