"""Generic model for email marketing.

Developed for Air Seychelles originally but should in no way
be segment-specific.  Examples may use airline-relevant scenarios.

A Lead is someone you might want to send emails to.  The email
address is required; other contact fields are provided but not
required.

The main classifications are:

role:  traveller, staff
country:  country of residence of the lead
region:  could be used for e.g. Europe, Southern Africa, Far East.


"""
import string
import datetime
from hashlib import md5

from django.conf import settings
from django.db import models
from django.contrib.auth.models import User

from mailer.models import DontSendEntry

from .fields import CountryField

try:
    import tinymce
    _HTML_FIELD = tinymce.models.HTMLField
except:
    _HTML_FIELD = models.TextField


# Set CRM_DEFAULT_ROLE in your settings otherwise 'USER' is used which is one of the initial roles in initial_data.json
CRM_DEFAULT_ROLE = getattr(settings, 'CRM_DEFAULT_ROLE', 'USER')


class Role(models.Model):
    id = models.CharField(max_length=20, primary_key=True, verbose_name='role', help_text="Code name")
    name = models.CharField(max_length=50, help_text="Display name")

    def __unicode__(self):
        return self.name

    def save(self, *args, **kwargs):
        self.id = self.id.upper().replace(' ','_')
        super(Role, self).save(*args, **kwargs)


class Language(models.Model):
    id = models.CharField(max_length=2, primary_key=True, verbose_name='language', help_text="Two-letter code name")
    name = models.CharField(max_length=50, help_text="Display name")

    def __unicode__(self):
        return self.name

    def save(self, *args, **kwargs):
        self.id = self.id.upper().replace(' ','_')
        super(Language, self).save(*args, **kwargs)


ID_CHARS = string.ascii_lowercase + string.digits + '_'

class CRMTag(models.Model):
    """General collection of tags to apply to leads."""

    id = models.CharField(max_length=20, primary_key=True, verbose_name='tag')
    description = models.CharField(max_length=100, blank=True, default='', help_text="Put help here for when to use this tag")

    def __unicode__(self):
        if self.description:
            return '%s (%s)' % (self.id, self.description)
        else:
            return self.id

    def save(self, *args, **kwargs):
        #normalise to have no spaces
        id = self.id.lower().replace(' ','_')
        id2 = ''
        for ch in id:
            if ch in ID_CHARS:
                id2 += ch
        self.id = id2
        super(CRMTag, self).save(*args, **kwargs)


class Communication(models.Model):
    subject = models.CharField(max_length=100, help_text="This will appear as the subject line in the receiver's email client")
    message_html = _HTML_FIELD(help_text="You should have prepared your HTML in an external editor before pasting it here")
    message_plain = models.TextField(help_text="This should only contain plain text with no HTML markup for people who do not have HTML email display enabled in their client")
    #audit trail
    created = models.DateTimeField(editable=False)
    updated = models.DateTimeField(editable=False)
    #sender = models.EmailField(blank=True, null=True)

    def __unicode__(self):
        return '%d: %s' % (self.id, self.subject)

    def save(self):
        if not self.id or not self.created:
            self.created = datetime.datetime.today()
        self.updated = datetime.datetime.today()
        super(Communication, self).save()

    def get_contents_preview(self):
        "Return some of the text, for use in the admin"
        return self.message_plain[0:50] + '...'
    get_contents_preview.short_description = "Plain text begins with..."

    def get_warnings(self):
        warnings = []
        if '{{unsubscribe_url}}' not in self.message_html:
            warnings.append('Message HTML: There is no URL for the recipient to unsubscribe - {{unsubscribe_url}}')
        if '{{unsubscribe_url}}' not in self.message_plain:
            warnings.append('Message Plain: There is no URL for the recipient to unsubscribe - {{unsubscribe_url}}')
        if '{{tracking_image}}' not in self.message_html:
            warnings.append('Message HTML: There is no tracking image included to see which people read the emails - {{tracking_image}}')
        return warnings

    def short_check_code(self):
        key = settings.SECRET_KEY
        code_md5 = md5('communication' + str(self.id) + key).hexdigest()
        return code_md5[-3:]



class Lead(models.Model):
    "Someone we might send emails to."    
    email = models.EmailField(unique=True)
    role = models.ForeignKey(Role, default=CRM_DEFAULT_ROLE)

    country = CountryField(blank=True)
    language = models.ForeignKey(Language, default="EN")

    tags = models.ManyToManyField(CRMTag, blank=True)

    #contact details fields - all optional    
    first_name = models.CharField(max_length=50, blank=True)
    middle_name = models.CharField(max_length=50, blank=True)
    last_name = models.CharField(max_length=50, blank=True)
    department = models.CharField(max_length=40, blank=True)
    job_title = models.CharField(max_length=50, blank=True)
    company = models.CharField(max_length=100, blank=True)

    business_street = models.CharField(max_length=50, blank=True)
    business_city = models.CharField(max_length=20, blank=True)
    business_country = models.CharField(max_length=20, blank=True)

    other_street = models.CharField(max_length=50, blank=True)
    other_city = models.CharField(max_length=20, blank=True)
    other_country = models.CharField(max_length=20, blank=True)

    business_fax = models.CharField(max_length=20, blank=True)
    business_phone = models.CharField(max_length=20, blank=True)
    mobile_phone = models.CharField(max_length=20, blank=True)
    other_phone = models.CharField(max_length=20, blank=True)

    email_display_name = models.CharField(max_length=30, blank=True)
    email_2_address = models.EmailField(blank=True)
    email_2_display_name = models.CharField(max_length=30, blank=True)

    #control fields
    has_bought = models.BooleanField(help_text='Has bought from us in the past', default=False)
    last_purchased = models.DateField(blank=True, null=True)
    active = models.BooleanField(default=True, help_text='Can be emailed; not unsubscribed')

    #audit trail
    created = models.DateTimeField(editable=False)
    created_by = models.ForeignKey(User, blank=True, null=True, related_name='leads_created')
    updated = models.DateTimeField(editable=False)
    updated_by = models.ForeignKey(User, blank=True, null=True, related_name='leads_updated')

    email_response = models.DateTimeField(editable=False, blank=True, null=True)
    email_response_communication = models.ForeignKey(Communication, blank=True, null=True)

    industry = models.CharField("Industry sector", max_length=200, blank=True)
    purpose = models.CharField("Use Reportlab for", max_length=200, blank=True)

    def unsubscribe(self, reason):
        "Mark this lead as unsubscribed - no further emails"
        if DontSendEntry.objects.filter(to_address=self.email).count() == 0:
            dont_send = DontSendEntry(to_address=self.email)
            dont_send.save()

        if self.active:
            self.active = False
            self.save()

    def __unicode__(self):
        return '%s %s (%s)' % (self.first_name, self.last_name, self.email)

    def save(self,*args,**kwargs):
        if not self.id or not self.created:
            self.created = datetime.datetime.today()
        self.updated = datetime.datetime.today()
        super(Lead, self).save(*args,**kwargs)

    def short_check_code(self):
        key = settings.SECRET_KEY
        code_md5 = md5('lead' + str(self.id) + key).hexdigest()
        return code_md5[-3:]

    def update_email_response(self, communication_id=None):
        self.email_response = datetime.datetime.today()
        if communication_id:
            #communication = Communication.objects.get(id=communication_id)
            if not self.email_response_communication or communication_id > self.email_response_communication:
                self.email_response_communication_id = communication_id
        self.save()

    def email_responses(self):
        return 'communication: %s (%s)' % (self.email_response_communication.id, self.email_response.strftime("%G-%m-%d %R"))

    def _email_responded(self):
        if self.email_response:
            return True
        return False
    email_responded = property(_email_responded)


class EmailJob(models.Model):
    communication = models.ForeignKey(Communication)
    tag = models.ForeignKey(CRMTag)
    created = models.DateTimeField(editable=False)
    created_by = models.ForeignKey(User, limit_choices_to={'is_staff': True}, blank=True, null=True, related_name='leads_job_created')
    queued = models.BooleanField(help_text='Email content has been generated for each lead and added to the messages queue by prepare_send management command (cron job).')
    ignore_previously_emailed = models.BooleanField(help_text='Only email a lead if they\'ve never had an email from us before.')
    ignore_previously_emailed_with_same_subject = models.BooleanField(help_text='Only email a lead if they\'ve not had an email with this subject line before.')

    def save(self):
        if not self.id or not self.created:
            self.created = datetime.datetime.today()
        super(EmailJob, self).save()

    def __unicode__(self):
        return '%d: %s -> %s' % (self.id, self.communication.subject, self.tag)


class LinkAddress(models.Model):
    """
    Stores all links that are included in emails. We rewrite them all so emails link to /redirect/1aaa/2bbb/3ccc and we can track the Lead as active.
    The '3ccc' section is the LinkAddress ID and it's checksum. This is a lot shorter than embedding the whole URL in our URL.
    """
    address = models.CharField(max_length=250, blank=True)
    created = models.DateTimeField(editable=False)

    def save(self):
        if not self.id or not self.created:
            self.created = datetime.datetime.today()
        super(LinkAddress, self).save()

    def short_check_code(self):
        key = settings.SECRET_KEY
        code_md5 = md5('linkaddress' + str(self.id) + key).hexdigest()
        return code_md5[-3:]


