from django.db import models
from django.conf import settings
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _, pgettext_lazy
from django.core.urlresolvers import reverse
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import fields
from oscar.core.loading import get_model

from oscar.models.fields import ExtendedURLField


# Linking models - these link promotions to content (eg pages, or keywords)


class LinkedPromotion(models.Model):

    # We use generic foreign key to link to a promotion model
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = fields.GenericForeignKey('content_type', 'object_id')

    position = models.CharField(_("Position"), max_length=100,
                                help_text="Position on page")
    display_order = models.PositiveIntegerField(_("Display Order"), default=0)
    clicks = models.PositiveIntegerField(_("Clicks"), default=0)
    date_created = models.DateTimeField(_("Date Created"), auto_now_add=True)

    class Meta:
        abstract = True
        app_label = 'promotions'
        ordering = ['-clicks']
        verbose_name = _("Linked Promotion")
        verbose_name_plural = _("Linked Promotions")

    def record_click(self):
        self.clicks += 1
        self.save()
    record_click.alters_data = True


@python_2_unicode_compatible
class PagePromotion(LinkedPromotion):
    """
    A promotion embedded on a particular page.
    """
    page_url = ExtendedURLField(
        _('Page URL'), max_length=128, db_index=True, verify_exists=True)

    def __str__(self):
        return u"%s on %s" % (self.content_object, self.page_url)

    def get_link(self):
        return reverse('promotions:page-click',
                       kwargs={'page_promotion_id': self.id})

    class Meta(LinkedPromotion.Meta):
        verbose_name = _("Page Promotion")
        verbose_name_plural = _("Page Promotions")


class KeywordPromotion(LinkedPromotion):
    """
    A promotion linked to a specific keyword.

    This can be used on a search results page to show promotions
    linked to a particular keyword.
    """

    keyword = models.CharField(_("Keyword"), max_length=200)

    # We allow an additional filter which will let search query matches
    # be restricted to different parts of the site.
    filter = models.CharField(_("Filter"), max_length=200, blank=True)

    def get_link(self):
        return reverse('promotions:keyword-click',
                       kwargs={'keyword_promotion_id': self.id})

    class Meta(LinkedPromotion.Meta):
        verbose_name = _("Keyword Promotion")
        verbose_name_plural = _("Keyword Promotions")

    # Different model types for each type of promotion


class AbstractPromotion(models.Model):
    """
    Abstract base promotion that defines the interface
    that subclasses must implement.
    """
    _type = 'Promotion'
    keywords = fields.GenericRelation(KeywordPromotion,
                                      verbose_name=_('Keywords'))
    pages = fields.GenericRelation(PagePromotion, verbose_name=_('Pages'))

    class Meta:
        abstract = True
        app_label = 'promotions'
        verbose_name = _("Promotion")
        verbose_name_plural = _("Promotions")

    @property
    def type(self):
        return _(self._type)

    @classmethod
    def classname(cls):
        return cls.__name__.lower()

    @property
    def code(self):
        return self.__class__.__name__.lower()

    def template_name(self):
        """
        Returns the template to use to render this promotion.
        """
        return 'promotions/%s.html' % self.code

    def template_context(self, request):
        return {}

    @property
    def content_type(self):
        return ContentType.objects.get_for_model(self)

    @property
    def num_times_used(self):
        ctype = self.content_type
        page_count = PagePromotion.objects.filter(content_type=ctype,
                                                  object_id=self.id).count()
        keyword_count \
            = KeywordPromotion.objects.filter(content_type=ctype,
                                              object_id=self.id).count()
        return page_count + keyword_count


@python_2_unicode_compatible
class RawHTML(AbstractPromotion):
    """
    Simple promotion - just raw HTML
    """
    _type = 'Raw HTML'
    name = models.CharField(_("Name"), max_length=128)

    # Used to determine how to render the promotion (eg
    # if a different width container is required).  This isn't always
    # required.
    display_type = models.CharField(
        _("Display type"), max_length=128, blank=True,
        help_text=_("This can be used to have different types of HTML blocks"
                    " (eg different widths)"))
    body = models.TextField(_("HTML"))
    date_created = models.DateTimeField(auto_now_add=True)

    class Meta:
        app_label = 'promotions'
        verbose_name = _('Raw HTML')
        verbose_name_plural = _('Raw HTML')

    def __str__(self):
        return self.name


@python_2_unicode_compatible
class Image(AbstractPromotion):
    """
    An image promotion is simply a named image which has an optional
    link to another part of the site (or another site).

    This can be used to model both banners and pods.
    """