from __future__ import unicode_literals

from django.core.validators import MinValueValidator
from django.db import models
from django.urls import reverse
from django.utils import timezone
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _

from ads.conf import settings
from ads.managers import AdManager


class Advertiser(models.Model):
    """ A Model for our Advertiser.  """
    company_name = models.CharField(
        verbose_name=_(u'Company Name'), max_length=255)
    website = models.URLField(verbose_name=_(u'Company Site'))
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL,
        verbose_name=_('Created By'))

    class Meta:
        verbose_name = _('Advertiser')
        verbose_name_plural = _('Advertisers')
        ordering = ('company_name',)

    def __str__(self):
        return self.company_name

    def get_website_url(self):
        return self.website


class Category(models.Model):
    """ a Model to hold the different Categories for adverts """
    title = models.CharField(
        verbose_name=_('Title'), max_length=255)
    description = models.TextField(
        verbose_name=_('Description'), blank=True)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL,
        verbose_name=_('Created By'))

    class Meta:
        verbose_name = _('Category')
        verbose_name_plural = _('Categories')
        ordering = ('title',)

    def __str__(self):
        return self.title


def now_plus_1_day():
    return timezone.now() + timezone.timedelta(days=1)


class Ad(models.Model):
    """
    This is our base model, from which all ads will inherit.
    The manager methods for this model will determine which ads to
    display return etc.
    """
    title = models.CharField(verbose_name=_('Title'), max_length=255)
    url = models.URLField(verbose_name=_('Advertised URL'))

    publication_date = models.DateTimeField(
        verbose_name=_('Start showing'),
        default=timezone.now)
    publication_date_end = models.DateTimeField(
        verbose_name=_('Stop showing'),
        default=now_plus_1_day)

    # Relations
    advertiser = models.ForeignKey(
        Advertiser, on_delete=models.CASCADE, verbose_name=_("Ad Provider"))
    category = models.ForeignKey(
        Category, on_delete=models.CASCADE,
        verbose_name=_("Category"), blank=True, null=True)
    zone = models.CharField(
        verbose_name=_('Zone'), max_length=100)
    weight = models.IntegerField(
        verbose_name=_('Weight'),
        help_text=_('Weight of the ad relative to other ads '
                    'in the same zone.<br />'
                    'Ad with higher weight will be '
                    'displayed more frequently.'),
        default=1,
        validators=[MinValueValidator(1)])

    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, null=True, on_delete=models.SET_NULL,
        verbose_name=_('Created By'))

    objects = AdManager()

    class Meta:
        verbose_name = _('Ad')
        verbose_name_plural = _('Ads')

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('ads:ad-click', kwargs={
            'pk': self.id})


class AdImage(models.Model):
    ad = models.ForeignKey(
        Ad, on_delete=models.CASCADE, verbose_name=_('Ad'),
        related_name='images')
    device = models.CharField(
        verbose_name=_('Device'), max_length=2, choices=settings.ADS_DEVICES)
    image = models.ImageField(verbose_name=_('Image'), max_length=255)

    @property
    def size(self):
        size = settings.ADS_ZONES.get(self.ad.zone, {}). \
            get('ad_size', {}). \
            get(self.device, None)
        return size or settings.ADS_DEFAULT_AD_SIZE

    def __str__(self):
        return self.get_device_display()


class Impression(models.Model):
    """
    The AdImpression Model will record every time the ad is loaded on a page
    """
    ad = models.ForeignKey(
        Ad, on_delete=models.CASCADE, verbose_name=_('Ad'),
        related_name='impressions')
    impression_date = models.DateTimeField(
        verbose_name=_('When'), auto_now_add=True)
    source_ip = models.GenericIPAddressField(
        verbose_name=_('Source IP Address'), null=True, blank=True)
    session_id = models.CharField(
        verbose_name=_('Source Session ID'),
        max_length=40, null=True, blank=True)

    class Meta:
        verbose_name = _('Ad Impression')
        verbose_name_plural = _('Ad Impressions')
        index_together = (
            ('ad', 'session_id', )
        )

    def __str__(self):
        return force_text(self.ad)


class Click(models.Model):
    """
    The AdClick model will record every click that a add gets
    """
    ad = models.ForeignKey(
        Ad, on_delete=models.CASCADE, verbose_name=_('Ad'),
        related_name='clicks')
    click_date = models.DateTimeField(
        verbose_name=_('When'), auto_now_add=True)
    source_ip = models.GenericIPAddressField(
        verbose_name=_('Source IP Address'), null=True, blank=True)
    session_id = models.CharField(
        verbose_name=_('Source Session ID'),
        max_length=40, null=True, blank=True)

    class Meta:
        verbose_name = _('Ad Click')
        verbose_name_plural = _('Ad Clicks')
        index_together = (
            ('ad', 'session_id', )
        )

    def __str__(self):
        return force_text(self.ad)