from django.db import models
from django.contrib.auth.models import User
from modules.core.encryption import EncryptedCharField

from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.core.urlresolvers import reverse

from datetime import date
from signals import registration_payment_completed, registration_completed, registration_invoice_completed, registration_member_referrers, member_invoice_paid, member_admin_approved
from signals import non_member_registered, bulk_email, membership_lapsed, membership_renewal, membership_expired, membership_suspended
from signals import renewal_confirmation, renewal_other_confirmation, renewal_invoice_confirmation, renewal_direct_debit_confirmation, direct_debit_updated, details_updated

from modules.notifications.models import EmailTemplate, send_mail, AdminMessage
from modules.abstracts.models import AbstractSubmission, AbstractSubmissionReview
from modules.papers.models import PaperSubmission

import os

fs = FileSystemStorage(location=settings.PRIVATE_FILES)


class MemberType(models.Model):

    SUBSCRIPTION_LENGTH_CHOICES = (
        (u'3-months', '3 Months'),
        (u'6-months', '6 Months'),
        (u'12-months', '12 Months'),
        (u'untimed', 'Untimed'),
    )

    name = models.CharField(max_length=200)
    order = models.IntegerField(default=0)
    description = models.TextField(blank=True)
    apply_online = models.BooleanField(default=False)
    new_fee = models.FloatField(verbose_name='Membership fee for New Members')
    renewal_fee = models.FloatField(verbose_name='Renewal fee')
    dd_discount = models.FloatField(verbose_name='Discount when renewing via Direct Debit')
    student = models.BooleanField(default=False)

    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ['order']

    def get_members(self):
        members = Member.objects.filter(member_type=self, member_status='current', user_type='member', approved=True)
        return members


class MemberGroup(models.Model):

    name = models.CharField(max_length=200)
    order = models.IntegerField(default=0)
    members = models.ManyToManyField('Member', blank=True)

    def __unicode__(self):
        return self.name


class Member(models.Model):

    USER_TYPE_CHOICES = (
        (u'member', u'Member'),
        (u'non-member', u'Non Member'),
    )

    MEMBER_STATUS_CHOICES = (
        (u'pending', u'Pending'),
        (u'current', u'Current'),
        (u'suspended', u'Suspended'),
        (u'lapsed', u'Lapsed'),
        (u'archived', u'Archived'),
    )

    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'),
    )

    PAYMENT_TYPE_CHOICES = (
        (u'bacs', u'BACS'),
        (u'standing_order', u'Standing Order'),
        (u'cheque', u'Cheque'),
        (u'credit_card', u'Credit Card'),
    )

    TRAINEE_CHOICES = (
        (u'AVS', u'AVS'),
        (u'Modernising Scientific Careers (Healthcare Scientist)', u'Modernising Scientific Careers (Healthcare Scientist)'),
        (u'Other', u'Other'),
    )

    user = models.ForeignKey(User)
    user_type = models.CharField(max_length=100, choices=USER_TYPE_CHOICES, default='member')
    member_type = models.ForeignKey(MemberType, verbose_name='Type of Membership Required', blank=True, null=True, on_delete=models.SET_NULL)
    registered = models.DateTimeField(blank=True, null=True)
    last_updated = models.DateTimeField(auto_now=True, blank=True, null=True)
    raw_password = models.CharField(max_length=100, blank=True, null=True)
    complete = models.BooleanField(default=False)

    # member registration fields
    approved = models.BooleanField(default=False)
    complete = models.BooleanField(default=False)
    paid = models.BooleanField(default=False)
    payment_type = models.CharField(max_length=20, blank=True, null=True, choices=PAYMENT_TYPE_CHOICES)

    # status (for renewals etc)
    member_status = models.CharField(max_length=100, choices=MEMBER_STATUS_CHOICES, default='current')
    renewal_message_date = models.DateField(blank=True, null=True)
    num_reminders = models.IntegerField(default=0)
    lapsed_date = models.DateField(blank=True, null=True)
    expiry_date = models.DateField(blank=True, null=True)

    unique_key = models.CharField(max_length=200, blank=True, null=True)
    requires_password_reset = models.BooleanField(default=True)
    temp_password = models.BooleanField(default=False)
    temp_email = models.BooleanField(default=False)
    membership_number = models.IntegerField(blank=True, null=True)

    category = models.CharField(max_length=10, blank=True, null=True)
    chapter = models.CharField(max_length=10, blank=True, null=True)
    previous_member_type = models.CharField(max_length=10, blank=True, null=True)
    date_added = models.DateField(blank=True, null=True)
    previous_name = models.TextField(blank=True, null=True)

    username = models.CharField(max_length=200, blank=True, null=True)

    # fields for application form
    title = models.CharField(max_length=10, choices=TITLE_CHOICES, blank=True, null=True)
    given_name = models.CharField(max_length=200, blank=True, null=True, verbose_name='First Name')
    surname = models.CharField(max_length=200, blank=True, null=True)

    date_of_birth = models.DateField(blank=True, null=True)

    # hospital addresses
    job_title = models.CharField(max_length=200, blank=True, null=True)
    institution_company = models.CharField(max_length=200, blank=True, null=True, verbose_name='Institution or Company')
    hospital = models.CharField(max_length=200, blank=True, null=True, verbose_name='Hospital or Affiliation')
    hospital_postcode = models.CharField(max_length=200, blank=True, null=True, verbose_name='Hospital Postcode')
    department_manager_email = models.EmailField(blank=True, null=True, verbose_name='Department Manager\'s Email')

    address_1 = EncryptedCharField(max_length=200, blank=True, null=True)
    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, blank=True, null=True)
    county = models.CharField(max_length=200, blank=True, null=True)
    country = models.ForeignKey('Country', related_name='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')

    # referrer fields
    know_existing = models.BooleanField(verbose_name='I do not know any existing members of the Society to act as my sponsors', default=False)

    referrer_email = models.EmailField(max_length=200, blank=True, null=True, verbose_name='Member Email Address')
    referrer_key = models.CharField(max_length=200, blank=True, null=True)
    referrer_approved = models.BooleanField(default=False)
    referrer_letter = models.FileField(upload_to='members', storage=fs, blank=True, null=True, verbose_name='Consent Form')

    referrer2_email = models.EmailField(max_length=200, blank=True, null=True, verbose_name='Sponsor 2 Email')
    referrer2_key = models.CharField(max_length=200, blank=True, null=True)
    referrer2_approved = models.BooleanField(default=False)

    referee_new_1_name = models.CharField(max_length=200, blank=True, null=True, verbose_name='Sponsor 1 Name')
    referee_new_1_details = models.TextField(blank=True, null=True, verbose_name='Sponsor 1 Contact Details')
    referee_new_2_name = models.CharField(max_length=200, blank=True, null=True, verbose_name='Sponsor 2 Name')
    referee_new_2_details = models.TextField(blank=True, null=True, verbose_name='Sponsor 2 Contact Details')

    trainee = models.BooleanField(default=False, verbose_name='Are you a Trainee')
    type_of_training = models.CharField(max_length=200, blank=True, null=True, choices=TRAINEE_CHOICES)
    avs_opt_in = models.BooleanField(default=False, verbose_name='Opt in to the AVS Status Search')
    other_training = models.CharField(max_length=200, blank=True, null=True)
    training_commencement = models.DateField(blank=True, null=True, verbose_name='Date of commencement of training')

    professional_certification = models.ManyToManyField('ProfessionalChoice', blank=True)
    avs_date = models.DateField(blank=True, null=True)
    other_professional_certification = models.CharField(max_length=200, blank=True, null=True)
    other_qualifications = models.ManyToManyField('QualificationChoice', blank=True)
    other_qualifications_other = models.CharField(max_length=200, blank=True, null=True)

    abide_by_terms = models.BooleanField(default=False, verbose_name='Please tick to confirm you abide by the societies \
        <a href="/media/resources/files/Code-Professional-Conduct.pdf">Code of Professional Conduct</a>.')
    agree_privacy = models.BooleanField(default=False, verbose_name='Please tick to confirm you have read and agree to the \
         <a href="/disclaimer/" target="_blank">Website Terms of Use and Privacy Notice</a>')

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

    # communication preferences
    mailing_list = models.BooleanField(default=False, verbose_name='Tick the box if you wish be added to the Mailing List')

    # invoice fields
    invoice_company_name = models.CharField(max_length=200, blank=True, null=True, verbose_name='Company Name')
    invoice_email = models.EmailField(max_length=200, blank=True, null=True, verbose_name='Email Address')

    first_login = models.BooleanField(default=False)

    class Meta:
        ordering = ['surname']

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

    def get_referrer_letter_filename(self):
        return os.path.basename(self.referrer_letter.name)

    def get_address(self):

        address = "%s<br/>" % (self.address_1)
        if self.address_2:
            address = "%s%s<br/>" % (address, self.address_2)
        address = "%s%s<br/>" % (address, self.town)
        if self.county:
            address = "%s%s<br/>" % (address, self.county)
        address = "%s%s<br/>%s<br/>" % (address, self.country, self.postcode)

        return address

    def is_current(self):

        if self.user_type == 'delegate':
            return True
        else:
            if self.approved:
                if self.member_status == 'current' or self.member_status == 'lapsed':
                    return True
                else:
                    return False
            else:
                return False

    def is_expiring(self):

        today = date.today()
        if self.user_type == 'member' and self.member_status == 'current':
            if self.expiry_date and self.expiry_date <= today:
                return True
        return False

    def get_letter_all(self, letter):

        members = Member.objects.filter(surname__istartswith=letter)
        if members.count() > 0:
            return True
        else:
            return False

    def get_letter_active(self, letter):

        members = Member.objects.filter(surname__istartswith=letter, approved=True, member_status='current', user_type='member').order_by('user__last_name')
        if members.count() > 0:
            return True
        else:
            return False

    def get_letter_archived(self, letter):

        members = Member.objects.filter(surname__istartswith=letter, member_status='archived', user_type='member').order_by('user__last_name')
        if members.count() > 0:
            return True
        else:
            return False

    def get_letter_active_delegate(self, letter):

        members = Member.objects.filter(surname__istartswith=letter, user_type='non-member').order_by('user__last_name')
        if members.count() > 0:
            return True
        else:
            return False

    def get_unread_activity(self):
        user_activity = UserActivity.objects.filter(member=self, read=False)
        return user_activity.count()

    def get_latest_subscription(self):

        member_subscriptions = MemberSubscription.objects.filter(member=self).order_by('-invoice_created')
        if member_subscriptions:
            return member_subscriptions[0]
        else:
            return False

    def get_current_subscription(self):

        today = date.today()
        subscriptions = MemberSubscription.objects.filter(member=self, start_date__lte=today, expiry_date__gte=today).order_by('-invoice_created')
        if subscriptions:
            return subscriptions[0]
        else:
            return False

    def get_subscriptions(self):
        subscriptions = MemberSubscription.objects.filter(member=self).order_by('-invoice_created')
        return subscriptions

    def get_registration_fee(self):

        if self.member_type:
            # today = date.today()
            # month = today.month
            fee = self.member_type.new_fee
            return fee
        else:
            return False

    def get_next_renewal_cost(self):
        if not self.member_type:
            cost = 0
        else:
            if self.get_direct_debit():
                cost = self.member_type.renewal_fee - self.member_type.dd_discount
            else:
                cost = self.member_type.renewal_fee

        return cost

    def get_direct_debit(self):
        direct_debit = MemberDirectDebit.objects.filter(member=self, status='current')
        if direct_debit:
            return True
        else:
            return False

    def get_emails(self):
        admin_messages = AdminMessage.objects.filter(add_to_locker=True, members=self)
        return admin_messages

    def can_access_email(self, email):

        if self in email.members.all() and email.add_to_locker:
            return True
        else:
            return False

    def get_abstract_submissions(self):
        abstract_submissions = AbstractSubmission.objects.filter(member=self, complete=True)
        return abstract_submissions

    def get_abstract_reviews(self):
        abstract_reviews = AbstractSubmissionReview.objects.filter(reviewer=self, sent=True)
        return abstract_reviews

    def get_paper_submissions(self):
        paper_submissions = PaperSubmission.objects.filter(member=self, complete=True)
        return paper_submissions

    def get_exam_applications(self):
        from modules.exam_application.models import ExamApplication
        exam_applications = ExamApplication.objects.filter(member=self).order_by('-start_time')
        return exam_applications

    def get_theory_exam_applications(self):
        from modules.theory_exam.models import TheoryExamApplication
        exam_applications = TheoryExamApplication.objects.filter(member=self).order_by('-start_time')
        return exam_applications

    def get_receipts(self):
        receipts = Receipt.objects.filter(member=self)
        return receipts

    def get_certificates(self):
        certificates = Certificate.objects.filter(member=self)
        return certificates

    # cpd functions
    def get_latest_cpd_year(self):
        from modules.cpd.models import CPDSubmissionYear
        today = date.today()
        try:
            cpd_year = CPDSubmissionYear.objects.get(member=self, end_date=date(today.year, 8, 31))
        except CPDSubmissionYear.DoesNotExist:
            cpd_year = CPDSubmissionYear(member=self, start_date=date(today.year-1, 9, 1), end_date=date(today.year, 8, 31))
            cpd_year.save()

        return cpd_year

    def get_current_cpd_status(self):
        from dateutil.relativedelta import relativedelta
        member_start_date = self.get_current_cpd_year_member()

        if self.registered:
            if self.registered.date() >= member_start_date:
                return 'not-required'
            registration_date = self.registered.date()
            today = date.today()
            cpd_years = relativedelta(today, registration_date).years
            if cpd_years > 3:
                cpd_years = 3
        else:
            cpd_years = 3

        total_points = self.get_current_cpd_points()
        average_points = float(total_points) / float(cpd_years)

        if average_points >= 10:
            return 'ok'
        else:
            return 'invalid'

    def get_current_avs_points(self):
        from modules.cpd.models import CPDSubmission
        total_points = 0

        start_date = self.get_current_cpd_year_start()
        end_date = self.get_current_cpd_year_end()

        cpd_submissions = CPDSubmission.objects.filter(member=self, date__gte=start_date, date__lte=end_date, approved=True)
        for submission in cpd_submissions:
            if submission.is_avs():
                total_points = total_points + submission.points_value
        return total_points

    def get_current_cpd_points(self):
        from modules.cpd.models import CPDSubmission

        start_date = self.get_current_cpd_year_start()
        end_date = self.get_current_cpd_year_end()

        total_points = 0

        cpd_submissions = CPDSubmission.objects.filter(member=self, date__gte=start_date, date__lte=end_date, approved=True)
        for submission in cpd_submissions:
            total_points = total_points + submission.points_value

        return total_points

    def get_current_cpd_year_member(self):
        today = date.today()
        if today.month >= 9:
            return date(today.year, 9, 1)
        else:
            return date(today.year - 1, 9, 1)

    def get_current_cpd_year_start(self):
        today = date.today()
        if today.month >= 9:
            return date(today.year - 3, 9, 1)
        else:
            return date(today.year - 4, 9, 1)

    def get_current_cpd_year_end(self):
        today = date.today()
        if today.month >= 9:
            return date(today.year, 8, 31)
        else:
            return date(today.year - 1, 8, 31)

    def get_future_cpd_status(self):

        from dateutil.relativedelta import relativedelta

        if self.registered:
            registration_date = self.registered.date()
            today = date.today()
            cpd_years = relativedelta(today, registration_date).years + 1
            if cpd_years > 3:
                cpd_years = 3
        else:
            cpd_years = 3

        total_points = self.get_future_cpd_points()
        average_points = float(total_points) / float(cpd_years)

        if average_points >= 10:
            return 'ok'
        else:
            return 'invalid'

    def get_future_avs_points(self):
        from modules.cpd.models import CPDSubmission
        total_points = 0

        start_date = self.get_future_cpd_year_start()
        end_date = self.get_future_cpd_year_end()

        cpd_submissions = CPDSubmission.objects.filter(member=self, date__gte=start_date, date__lte=end_date, approved=True)
        for submission in cpd_submissions:
            if submission.is_avs():
                total_points = total_points + submission.points_value
        return total_points

    def get_future_cpd_points(self):
        from modules.cpd.models import CPDSubmission

        start_date = self.get_future_cpd_year_start()
        end_date = self.get_future_cpd_year_end()

        total_points = 0

        cpd_submissions = CPDSubmission.objects.filter(member=self, date__gte=start_date, date__lte=end_date, approved=True)
        for submission in cpd_submissions:
            total_points = total_points + submission.points_value

        return total_points

    def get_future_cpd_remaining(self):
        from dateutil.relativedelta import relativedelta

        # start_date = self.get_future_cpd_year_start()
        # end_date = self.get_future_cpd_year_end()

        future_cpd_points = self.get_future_cpd_points()

        if self.registered:
            registration_date = self.registered.date()
            today = date.today()
            cpd_years = relativedelta(today, registration_date).years + 1
            if cpd_years > 3:
                cpd_years = 3
        else:
            cpd_years = 3

        required_points = 10 * cpd_years
        remaining = required_points - future_cpd_points
        return remaining

    def get_future_cpd_year_start(self):
        today = date.today()
        if today.month >= 9:
            return date(today.year - 2, 9, 1)
        else:
            return date(today.year - 3, 9, 1)

    def get_future_year(self):
        today = date.today()
        if today.month >= 9:
            return today.year
        else:
            return today.year - 1

    def get_future_cpd_year_end(self):
        today = date.today()
        if today.month >= 9:
            return date(today.year + 1, 8, 31)
        else:
            return date(today.year, 8, 31)

    def get_documents(self):
        documents = MemberDocument.objects.filter(member=self)
        return documents

    def get_avs(self):
        prof_certs = self.professional_certification.all().filter(admin_only=True)
        if prof_certs:
            return True
        else:
            return False


class AreaOfInterest(models.Model):

    name = models.CharField(max_length=200)

    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ['name']

    def get_members(self):
        members = Member.objects.filter(special_interest_groups=self, member_status='current', user_type='member', approved=True)
        return members


class ProfessionalChoice(models.Model):

    name = models.CharField(max_length=200)
    order = models.IntegerField(default=10)
    admin_only = models.BooleanField(default=False)

    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ['-admin_only', 'order']


class QualificationChoice(models.Model):

    name = models.CharField(max_length=200)
    order = models.IntegerField(default=10)

    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ['order']


class FurtherInformationMessage(models.Model):

    member = models.ForeignKey('Member')
    message = models.TextField(help_text='Please enter your message above, this will appear above the link for the member to resend their application.')
    created = models.DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return "%s %s" % (self.member, self.created)


class MemberTransaction(models.Model):

    member = models.ForeignKey('Member')
    name = models.CharField(max_length=200)
    transaction_date = models.DateField(blank=True, null=True)
    invoice_no = models.CharField(max_length=20, blank=True, null=True)
    item = models.IntegerField()
    transaction_type = models.CharField(max_length=20)
    batch = models.IntegerField()
    amount = models.FloatField()
    vat = models.FloatField()
    balance = models.FloatField()
    paid = models.FloatField()
    payment_method = models.CharField(max_length=100, blank=True, null=True)
    printed = models.CharField(max_length=100, blank=True, null=True)
    credit_note_id = models.CharField(max_length=100, blank=True, null=True)

    def __unicode__(self):
        return "%s - %s (%s)" % (self.member, self.name, self.transaction_date)


class MemberEvent(models.Model):

    STATUS_CHOICES = (
        (u'confirmed', u'Confirmed'),
        (u'cancelled', u'Cancelled'),
    )

    member = models.ForeignKey('Member')
    event_name = models.CharField(max_length=200)
    created = models.DateTimeField(auto_now_add=True)
    member_name = models.CharField(max_length=200)
    booking_type = models.CharField(max_length=20)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES)

    def __unicode__(self):
        return """%s - %s""" % (self.member_name, self.event_name)


class MemberContact(models.Model):

    member = models.ForeignKey('Member')
    contact_date = models.DateField()
    contact_type = models.CharField(max_length=200)
    category = models.CharField(max_length=200)
    subject = models.CharField(max_length=200)
    operator = models.CharField(max_length=100)
    closed = models.BooleanField(default=False)

    def __unicode__(self):
        return "%s - %s" % (self.member, self.subject)


class MemberCommittee(models.Model):

    member = models.ForeignKey('Member')
    committee = models.CharField(max_length=200)
    position_code = models.CharField(max_length=20, blank=True, null=True)
    position = models.CharField(max_length=200)
    start_date = models.DateField()
    end_date = models.DateField()

    def __unicode__(self):
        return "%s - %s - %s" % (self.member, self.committee, self.position)


class MemberClassification(models.Model):

    member = models.ForeignKey('Member')
    parent_classification = models.CharField(max_length=200, blank=True, null=True)
    classification = models.CharField(max_length=200)
    class_date = models.DateField()
    source = models.CharField(max_length=100, blank=True, null=True)

    def __unicode__(self):
        return """%s %s""" % (self.member, self.classification)


class MemberSubscription(models.Model):

    STATUS_CHOICES = (
        (u'archived', u'Archived'),
        (u'pending', u'Pending'),
        (u'current', u'Current'),
    )

    member = models.ForeignKey('Member')
    member_type = models.ForeignKey('MemberType', blank=True, null=True)
    subscription = models.CharField(max_length=200)
    amount = models.FloatField(verbose_name='Amount(GBP)')
    discount = models.FloatField(verbose_name='Discount(GBP)', default=0)
    total = models.FloatField(verbose_name='Total(GBP)')
    invoice_to = models.CharField(max_length=200)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES)
    start_date = models.DateField()
    expiry_date = models.DateField()
    invoice_created = models.DateField(blank=True, null=True, default=date.today)
    archived = models.BooleanField(default=False)
    method = models.CharField(max_length=200, blank=True, null=True, verbose_name='Payment Method')
    renew_membership = models.BooleanField(default=False, verbose_name='Renew the members membership when saved - will create Receipt and Email')

    def __unicode__(self):
        return "%s - %s" % (self.member, self.subscription)


class MemberDirectDebit(models.Model):

    STATUS_CHOICES = (
        (u'pending', u'Pending'),
        (u'current', u'Current'),
        (u'archived', u'Archived'),
    )

    SUBMISSION_CHOICES = (
        (u'01', u'New Submission'),
        (u'17', u'Existing Submission'),
    )

    COLLECTION_CHOICES = (
        (u'A', u'Annual (Single)'),
    )

    TYPE_CHOICES = (
        (u'UKDD', u'UK Direct Debit (BACS)'),
    )

    member = models.ForeignKey('Member')
    sort_code = EncryptedCharField(max_length=20, verbose_name='Sort Code')
    ac_name = models.CharField(max_length=100, verbose_name='Account Name')
    ac_no = EncryptedCharField(max_length=20, verbose_name='Account Number')
    collection = models.CharField(max_length=100, choices=COLLECTION_CHOICES, default='A')
    submission = models.CharField(max_length=100, choices=SUBMISSION_CHOICES, default='1')
    type = models.CharField(max_length=100, choices=TYPE_CHOICES, default='UKDD')

    old_sort_code = EncryptedCharField(max_length=20, verbose_name='Old Sort Code', blank=True, null=True)
    old_ac_name = models.CharField(max_length=100, verbose_name='Old Account Name', blank=True, null=True)
    old_ac_no = EncryptedCharField(max_length=20, verbose_name='Old Account Number', blank=True, null=True)

    status = models.CharField(default='pending', max_length=20, choices=STATUS_CHOICES)
    created = models.DateTimeField(auto_now_add=True)

    def get_cost(self):

        if self.member.member_type:
            member_type = self.member.member_type

            initial = member_type.renewal_fee
            discount = member_type.dd_discount
            cost = initial - discount

            return cost

        else:
            return 0

    def __unicode__(self):
        return "%s" % (self.member)


class MemberArrears(models.Model):

    member = models.ForeignKey('Member')

    name = models.CharField(max_length=200)
    description = models.TextField(verbose_name="Message")
    amount = models.FloatField()

    paid = models.BooleanField(default=False)
    created = models.DateTimeField(auto_now_add=True)

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


class Country(models.Model):

    CURRENCY_CHOICES = (
        (u'GBP', u'GBP'),
        (u'EUR', u'EUR')
    )

    name = models.CharField(max_length=100)
    order = models.IntegerField()
    iso_code = models.CharField(blank=True, null=True, max_length=20)
    currency = models.CharField(max_length=10, blank=True, null=True, choices=CURRENCY_CHOICES)

    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ('order', )


class UserActivity(models.Model):

    TYPE_CHOICES = (
        (u'general', u'General Notification'),
        (u'meeting-notification', u'Meeting Notification'),
        (u'voting-notification', u'Election Notification'),
        (u'member-notification', u'Member Notification'),
        (u'account-notification', u'Account Notification'),
        (u'certificate-notification', u'Certificate Notifications'),
        (u'receipt-notification', u'Receipt Notifications')
    )

    member = models.ForeignKey('Member')
    created = models.DateTimeField(auto_now_add=True)
    read = models.BooleanField(default=False)
    title = models.CharField(max_length=200)
    text = models.TextField()
    type = models.CharField(max_length=100, default='general', choices=TYPE_CHOICES)

    def __unicode__(self):
        return """%s - %s""" % (self.member, self.created)


class MemberResource(models.Model):

    member = models.ForeignKey('Member')
    created = models.DateTimeField(auto_now_add=True)
    resource = models.ForeignKey('resources.Resource')

    def __unicode__(self):
        return """%s - %s """ % (self.member, self.resource)


class MemberEmail(models.Model):

    sender = models.ForeignKey('Member', related_name='sender')
    recipient = models.ForeignKey('Member', related_name='receipient')
    message = models.TextField()
    created = models.DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return """%s - %s - %s""" % (self.sender, self.recipient, self.created)


class Receipt(models.Model):

    member = models.ForeignKey('Member')
    meeting_booking = models.ForeignKey('meeting_booking.MeetingBooking', blank=True, null=True)
    member_subscription = models.ForeignKey('MemberSubscription', blank=True, null=True)
    job_advert = models.ForeignKey('jobs.Job', blank=True, null=True, related_name='job_receipt', on_delete=models.SET_NULL)
    name = models.CharField(max_length=200)
    type = models.CharField(max_length=20, default='membership')
    created = models.DateTimeField(auto_now_add=True)
    file = models.FileField(upload_to='members/receipts', blank=True, null=True)
    amount_paid = models.CharField(max_length=20)
    start_date = models.DateField(blank=True, null=True)
    payment_type = models.CharField(max_length=20, blank=True, null=True)

    unique_key = models.CharField(max_length=20, blank=True, null=True)

    def __unicode__(self):
        return """%s %s""" % (self.member, self.created)


class Certificate(models.Model):

    member = models.ForeignKey('member')
    created = models.DateTimeField(auto_now_add=True)
    file = models.FileField(upload_to='members/certificates', blank=True, null=True)
    start_date = models.DateField(blank=True, null=True)
    end_date = models.DateField(blank=True, null=True)

    def __unicode__(self):
        return """%s %s""" % (self.member, self.start_date)


class MemberRenewal(models.Model):

    PAYMENT_TYPE_CHOICES = (
        (u'bacs', u'BACS'),
        (u'standing_order', u'Standing Order'),
        (u'cheque', u'Cheque'),
        (u'credit_card', u'Credit Card'),
    )

    member = models.ForeignKey('Member')
    payment_method = models.CharField(max_length=200, choices=PAYMENT_TYPE_CHOICES)
    created = models.DateTimeField(auto_now_add=True)
    paid = models.BooleanField(default=False)

    def __unicode__(self):
        return "%s Membership Renewal %s" % (self.member, self.created)


class MemberRenewalInvoice(models.Model):

    member = models.ForeignKey('Member')
    created = models.DateTimeField(auto_now_add=True)
    paid = models.BooleanField(default=False)

    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='renewal_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 Membership Renewal %s" % (self.member, self.created)


class MemberDocument(models.Model):

    member = models.ForeignKey('Member')
    title = models.CharField(max_length=200)
    document = models.FileField(storage=fs, upload_to='members/documents')
    created = models.DateTimeField(auto_now_add=True)

    def __unicode__(self):
        return self.title

    class Meta:
        ordering = ['-created']


def registration_invoice_completed_handler(sender, **kwargs):

    member = kwargs['member']

    # admin email
    try:
        template = EmailTemplate.objects.get(key='registration_invoice_completed_admin')
        if member.donation:
            donation_amount = '&pound;%s' % (member.donation_amount)
        else:
            donation_amount = 'No Donation'
        message = template.content % (
            member.given_name, member.surname, member.user.email, member.member_type.name, donation_amount, member.invoice_company_name, member.invoice_email,
            settings.URL, reverse('admin_members_pending'), settings.URL, reverse('admin_members_pending')
        )
        subject = template.subject

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

    try:
        template = EmailTemplate.objects.get(key='registration_completed_member')
        message = template.content
        subject = template.subject
        send_mail(template.key, subject, message, template.from_address.email_address, member.user.email)
    except Exception as e:
        raise e

    # email invoice (TO DO)


registration_invoice_completed.connect(registration_invoice_completed_handler, dispatch_uid="registration_invoice_completed")


def registration_completed_handler(sender, **kwargs):

    member = kwargs['member']

    # admin email
    try:
        template = EmailTemplate.objects.get(key='registration_completed_admin')

        message = template.content % (
            member.given_name, member.surname, member.user.email, member.member_type.name, member.payment_type, settings.URL,
            reverse('admin_members_pending'), settings.URL, reverse('admin_members_pending')
        )
        subject = template.subject

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

    try:
        template = EmailTemplate.objects.get(key='registration_completed_member')
        message = template.content
        subject = template.subject
        send_mail(template.key, subject, message, template.from_address.email_address, member.user.email)
    except Exception as e:
        raise e

    # email invoice (TO DO)


registration_completed.connect(registration_completed_handler, dispatch_uid="registration_completed")


def registration_payment_completed_handler(sender, **kwargs):

    member = kwargs['member']
    payment = kwargs['payment']
    receipt = kwargs['receipt']

    # admin email
    try:
        template = EmailTemplate.objects.get(key='registration_payment_completed_admin')
        message = template.content % (
            member.given_name, member.surname, member.user.email, member.member_type.name, payment.amount,
            settings.URL, reverse('admin_members_pending'), settings.URL, reverse('admin_members_pending')
        )
        subject = template.subject

        send_mail(template.key, subject, message, template.from_address.email_address, template.get_to_addresses())

    except Exception as e:
        raise e

    try:
        template = EmailTemplate.objects.get(key='registration_payment_completed_member')
        message = template.content
        subject = template.subject

        if receipt and receipt.file:
            send_mail(template.key, subject, message, template.from_address.email_address, template.get_to_addresses(), [], [receipt.file])
        else:
            send_mail(template.key, subject, message, template.from_address.email_address, member.user.email)
    except Exception as e:
        raise e


registration_payment_completed.connect(registration_payment_completed_handler, dispatch_uid="registration_payment_completed")


def registration_member_referrers_handler(sender, **kwargs):

    member = kwargs['member']

    try:
        email_address = member.referrer_email
        template = EmailTemplate.objects.get(key='registration_member_referrer')
        message = template.content % (
            member.given_name, member.surname,
            settings.URL, reverse('register_referrer_confirm', args=[member.referrer_key]),
            settings.URL, reverse('register_referrer_confirm', args=[member.referrer_key])
        )
        subject = template.subject

        send_mail(template.key, subject, message, template.from_address.email_address, email_address)

    except Exception as e:
        raise e


registration_member_referrers.connect(registration_member_referrers_handler, dispatch_uid="registration_member_referrers")


def member_invoice_paid_handler(sender, **kwargs):

    member = kwargs['member']
    receipt = kwargs['receipt']

    try:
        template = EmailTemplate.objects.get(key='member_invoice_complete')
        message = template.content
        subject = template.subject

        if receipt and receipt.file:
            send_mail(template.key, subject, message, template.from_address.email_address, member.user.email, [], [receipt.file])
        else:
            send_mail(template.key, subject, message, template.from_address.email_address, member.user.email)
    except Exception as e:
        raise e


member_invoice_paid.connect(member_invoice_paid_handler, dispatch_uid="member_invoice_paid")


def member_admin_approved_handler(sender, **kwargs):

    member = kwargs['member']
    certificate = kwargs['certificate']

    # send email to member to confirm full membership

    try:
        template = EmailTemplate.objects.get(key='member_approved')
        message = template.content
        subject = template.subject
        if certificate and certificate.file:
            send_mail(template.key, subject, message, template.from_address.email_address, member.user.email, [], [certificate.file])
        else:
            send_mail(template.key, subject, message, template.from_address.email_address, member.user.email)

    except Exception as e:
        raise e


member_admin_approved.connect(member_admin_approved_handler, dispatch_uid="member_admin_approved")


def non_member_registered_handler(sender, **kwargs):

    member = kwargs['member']
    # title = kwargs['title']

    try:
        template = EmailTemplate.objects.get(key='non_member_registered')
        message = template.content % (member.user.email, member.raw_password)
        template.send_email(message, member.user.email)
    except Exception as e:
        raise e


non_member_registered.connect(non_member_registered_handler, dispatch_uid="non_member_registered")


def details_updated_handler(sender, **kwargs):

    member = kwargs['member']
    updated_fields = kwargs['updated_fields']

    try:
        template = EmailTemplate.objects.get(key='details_updated_admin')

        field_updates = "<h3><strong>Updated Fields:</strong></h3>"

        for updated_field in updated_fields:
            field_updates = """%s<p><strong>%s</strong><br/>
<strong>Old</strong> %s <strong>New</strong> %s</p>
""" % (field_updates, updated_field['field'], updated_field['old'], updated_field['new'])

        message = template.content % (
            member.given_name, member.surname, member.user.email, field_updates,
            settings.URL, reverse('view_member', args=[member.id]), settings.URL, reverse('view_member', args=[member.id])
        )

        subject = template.subject

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


details_updated.connect(details_updated_handler, dispatch_uid="details_updated")


def membership_renewal_handler(sender, **kwargs):

    member = kwargs['member']

    template = EmailTemplate.objects.get(key='membership_renewal')
    message = template.content % (member.expiry_date.strftime("%d/%m/%y"))
    subject = template.subject
    send_mail(template.key, subject, message, template.from_address.email_address, member.user.email)


membership_renewal.connect(membership_renewal_handler, dispatch_uid="membership_renewal")


def membership_expired_handler(sender, **kwargs):

    member = kwargs['member']

    template = EmailTemplate.objects.get(key='membership_expired')
    message = template.content
    subject = template.subject
    send_mail(template.key, subject, message, template.from_address.email_address, member.user.email)


membership_expired.connect(membership_expired_handler, dispatch_uid="membership_expired")


def membership_lapsed_handler(sender, **kwargs):

    member = kwargs['member']

    template = EmailTemplate.objects.get(key='membership_lapsed')
    message = template.content % (member.expiry_date.strftime("%d/%m/%y"))
    subject = template.subject
    send_mail(template.key, subject, message, template.from_address.email_address, member.user.email)


membership_lapsed.connect(membership_lapsed_handler, dispatch_uid="membership_lapsed")


def membership_suspended_handler(sender, **kwargs):

    member = kwargs['member']

    template = EmailTemplate.objects.get(key='membership_suspended')
    message = template.content
    subject = template.subject
    send_mail(template.key, subject, message, template.from_address.email_address, member.user.email)


membership_suspended.connect(membership_suspended_handler, dispatch_uid="membership_suspended")


def renewal_confirmation_handler(sender, **kwargs):

    member = kwargs['member']
    subscription = kwargs['subscription']
    method = kwargs['method']
    receipt = kwargs['receipt']
    certificate = kwargs['certificate']
    notify_admin = kwargs['notify_admin']

    # admin email
    if notify_admin:
        template = EmailTemplate.objects.get(key='renewal_confirmation_admin')
        message = template.content % (member.given_name, member.surname, member.user.email, member.expiry_date.strftime("%d/%m/%Y"), member.member_type, subscription.amount, method)
        subject = template.subject

        send_mail(template.key, subject, message, template.from_address.email_address, template.get_to_addresses())

    # member email
    template = EmailTemplate.objects.get(key='renewal_confirmation')
    message = template.content % (member.expiry_date.strftime("%d/%m/%Y"))
    subject = template.subject

    if receipt and receipt.file and certificate and certificate.file:
        send_mail(template.key, subject, message, template.from_address.email_address, member.user.email, False, [receipt.file, certificate.file])
    else:
        send_mail(template.key, subject, message, template.from_address.email_address, member.user.email)


renewal_confirmation.connect(renewal_confirmation_handler, dispatch_uid="renwal_confirmation")


def renewal_other_confirmation_handler(sender, **kwargs):

    member = kwargs['member']
    renewal = kwargs['renewal']

    try:
        template = EmailTemplate.objects.get(key="renewal_other_confirmation_admin")
        message = template.content % (
            member.given_name, member.surname, member.user.email, member.member_type, renewal.get_payment_method_display(),
            settings.URL, reverse('admin_members_renewal'), settings.URL, reverse('admin_members_renewal')
        )
        subject = template.subject

        send_mail(template.key, subject, message, template.from_address.email_address, template.get_to_addresses())

    except Exception as e:
        raise e


renewal_other_confirmation.connect(renewal_other_confirmation_handler, dispatch_uid="renewal_other_confirmation")


def renewal_invoice_confirmation_handler(sender, **kwargs):

    member = kwargs['member']
    invoice = kwargs['invoice']

    template = EmailTemplate.objects.get(key="renewal_invoice_confirmation_admin")
    message = template.content % (
        member.given_name, member.surname, member.user.email, member.member_type, member.member_type,
        settings.URL, reverse('admin_members_view_renewal_invoice', args=[invoice.id]), settings.URL, reverse('admin_members_view_renewal_invoice', args=[invoice.id])
    )
    subject = template.subject

    send_mail(template.key, subject, message, template.from_address.email_address, template.get_to_addresses())


renewal_invoice_confirmation.connect(renewal_invoice_confirmation_handler, dispatch_uid="renewal_invoice_confirmation")


def renewal_direct_debit_confirmation_handler(sender, **kwargs):

    request = kwargs['request']
    member = kwargs['member']
    direct_debit = kwargs['direct_debit']

    # admin email
    template = EmailTemplate.objects.get(key='renewal_direct_debit_confirmation_admin')
    message = template.content % (
        member.given_name, member.surname, member.user.email, member.membership_number,
        request.META['HTTP_HOST'], reverse('admin_members_view_direct_debit', args=[direct_debit.id]), request.META['HTTP_HOST'], reverse('admin_members_view_direct_debit', args=[direct_debit.id])
    )
    subject = template.subject

    send_mail(template.key, subject, message, template.from_address.email_address, template.get_to_addresses())

    # member email
    template = EmailTemplate.objects.get(key='renewal_direct_debit_information')
    message = template.content
    subject = template.subject

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


renewal_direct_debit_confirmation.connect(renewal_direct_debit_confirmation_handler, dispatch_uid="renewal_direct_debit_confirmation")


def direct_debit_updated_handler(sender, **kwargs):

    request = kwargs['request']
    member = kwargs['member']
    direct_debit = kwargs['direct_debit']

    # admin email
    template = EmailTemplate.objects.get(key='direct_debit_updated_admin')
    message = template.content % (
        member.given_name, member.surname, member.user.email, member.membership_number,
        request.META['HTTP_HOST'], reverse('admin_members_view_direct_debit', args=[direct_debit.id]), request.META['HTTP_HOST'], reverse('admin_members_view_direct_debit', args=[direct_debit.id])
    )
    subject = template.subject

    send_mail(template.key, subject, message, template.from_address.email_address, template.get_to_addresses())


direct_debit_updated.connect(direct_debit_updated_handler, dispatch_uid="direct_debit_updated")


def bulk_email_handler(sender, **kwargs):

    admin_message = kwargs['admin_message']

    email_content = admin_message.message
    from_address = admin_message.sender

    if admin_message.test_recipient:
        subject = '%s - TEST' % (admin_message.subject)
        bcc_addresses = [admin_message.test_recipient]
    else:
        subject = admin_message.subject
        bcc_addresses = []

        members = []

        if admin_message.email_expired:
            today = date.today()
            members = Member.objects.filter(expiry_date__lte=today, user_type='member', member_status='current')
        else:
            if admin_message.groups.all():

                for group in admin_message.groups.all():
                    for member in group.members.all():
                        members.append(member)
            else:
                members = Member.objects.filter(user_type='member', approved=True, member_status='current', temp_email=False)

            if admin_message.types.all():
                final_members = []
                for member in members:
                    if member.member_type in admin_message.types.all():
                        final_members.append(member)
                members = final_members

            if admin_message.add_to_locker:
                for member in members:
                    email_text = '<strong>Subject</strong> %s <a href="%s">View the email</a>' % (subject, reverse('account_view_email', args=[admin_message.id]))
                    member_notification = UserActivity(member=member, title='You have a new Email Alert', text=email_text, type='member-notification')
                    member_notification.save()
            admin_message.save()

        for member in members:
            admin_message.members.add(member)
            email = member.user.email
            if email != '':
                bcc_addresses.append(email)

        admin_message.save()

    if admin_message.get_attachments():
        attachments = []
        for attachment in admin_message.get_attachments():
            attachments.append(attachment.file)
    else:
        attachments = False

    if bcc_addresses:
        send_mail('bulk-email', subject, email_content, from_address, from_address, bcc_addresses, attachments, from_address)


bulk_email.connect(bulk_email_handler, dispatch_uid="bulk_email")
