import os
from urlparse import urlparse

from django.core.urlresolvers import reverse
from django.conf import settings
from django.db import models
from django.dispatch import receiver
from django.test.client import Client
from django.utils.translation import ugettext_lazy as _

from textplusstuff.fields import TextPlusStuffField
from versatileimagefield.fields import VersatileImageField, PPOIField

url_prefix = getattr(settings, 'STACKSPAGE_URL_PREFIX', '/').rstrip('/')


class StacksPageBase(models.Model):
    """
    A base model for shared attributes/logic across stacks_page models
    """
    date_created = models.DateTimeField(
        auto_now_add=True
    )
    date_modified = models.DateTimeField(
        auto_now=True
    )

    class Meta:
        abstract = True


class StacksPage(StacksPageBase):
    """
    Represents a single HTML page.
    """
    title = models.CharField(
        _('Page Title'),
        max_length=100,
        help_text=(
            'The title of the page. Currently only used for SEO.'
        )
    )
    slug = models.SlugField(
        _('Page Slug'),
        unique=True
    )
    description = models.TextField(
        _('Page Description'),
        help_text=(
            'A short description of the page. Currently only used for SEO.'
        )
    )
    twitter_share_text = models.CharField(
        _('Twitter Share Text'),
        max_length=110,
        blank=True,
        help_text=(
            "The text to use when sharing this page to Twitter. Limited to "
            "110 characters."
        )
    )
    canonical_image = VersatileImageField(
        _('Canonical Image'),
        upload_to='images/canonical',
        max_length=300,
        help_text=(
            'An image that represents this page. Is used when this page is '
            'shared on social media.'
        ),
        blank=True,
        ppoi_field='canonical_image_ppoi'
    )
    canonical_image_ppoi = PPOIField()
    publish = models.BooleanField(
        _('Publish Live on Save?'),
        default=False,
        help_text=(
            'Signifies whether this page is viewable to the public.'
        )
    )
    template_path = models.CharField(
        max_length=200,
        default='stacks_page/default_page_template.html',
        help_text=(
            'The path to the template (within this django project) used to '
            'render this page. Used only by developers.'
        )
    )
    live_url = models.URLField(
        _('Live URL'),
        max_length=250,
        blank=True,
        help_text='The URL this page will live at once live in production.'
    )

    class Meta:
        verbose_name = _('Page')
        verbose_name_plural = _('Pages')

    def __unicode__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('stackspage-detail', kwargs={'slug': self.slug})


class StacksPageSection(StacksPageBase):
    """
    Represents a 'section' of content on a page.
    """
    page = models.ForeignKey(
        StacksPage,
        verbose_name=_('Page'),
        related_name='sections'
    )
    title_section = models.CharField(
        _('Title'),
        max_length=140,
        help_text=(
            'The title of this section.'
        )
    )
    title_menu = models.CharField(
        max_length=80,
        help_text=(
            "The 'menu title' of this section."
        )
    )
    slug = models.SlugField(
        _('Section Slug'),
        max_length=80,
    )
    order = models.PositiveIntegerField(
        _('Order'),
        help_text=(
            'The order this page appears on the parent page.'
        )
    )
    content = TextPlusStuffField(
        _('Content'),
        blank=True,
        null=True,
        help_text=('The content of this page section.')
    )
    twitter_share_text = models.CharField(
        _('Twitter Share Text'),
        max_length=110,
        blank=True,
        help_text=(
            "The text to use when sharing this page to Twitter. Limited to "
            "110 characters. If this field is blank the text entered in the "
            "the parent page's Twitter Share Text will be used."
        )
    )

    class Meta:
        verbose_name = _('Page Section')
        verbose_name_plural = _('Page Sections')
        ordering = ('page', 'order')
        unique_together = ('page', 'slug')

    def __unicode__(self):
        return "{page_title} #{order} {section_title}".format(
            page_title=self.page.title,
            order=self.order,
            section_title=self.title_menu
        )


def get_StacksPage_static_save_location(instance):
    """
    Returns a 2-tuple of the folder and filename of where a StacksPage
    should be saved to when publishing it as a static file based on the value
    of instance.live_url.

    Example if instance.live_url is:
    'http://www.pbs.org/wgbh/masterpiece/downtonabbey/downton-experience.html'

    Then `folder` would be 'wgbh/masterpiece/downtonabbey/' and
    `filename` would be 'downton-experience.html'
    """
    url_parsed = urlparse(instance.live_url)
    folder, filename = os.path.split(url_parsed.path)
    folder = folder.lstrip('/')
    if not filename:
        filename = 'index.html'
    return folder, filename


def get_StacksPage_local_save_path(instance):
    """
    Determines the path on disc to save static renditions of StacksPage
    instances.
    """
    folder, filename = get_StacksPage_static_save_location(instance)
    build_directory = getattr(settings, 'STACKSPAGE_BUILD_DIRECTORY', '')
    to_save_dir = os.path.join(build_directory, folder)
    if not os.path.exists(to_save_dir):
        os.makedirs(to_save_dir)
    return os.path.abspath(
        os.path.join(to_save_dir, filename)
    )


@receiver(models.signals.post_save, sender=StacksPage)
def save_static_rendition(sender, instance, **kwargs):
    """Saves a static version of a StacksPage instance."""
    if instance.live_url and instance.publish is True:
        client = Client()
        url = instance.get_absolute_url().replace(url_prefix, '', 1)
        request = client.get(url)
        file_location = get_StacksPage_local_save_path(instance)
        f = open(file_location, 'w')
        f.write(request.content)
        f.close()
