from django.db import models
from django.db.models import Q
from django.db.models import DateField, \
    CharField, \
    BooleanField, \
    IntegerField
from solo.models import SingletonModel
from markdownx.models import MarkdownxField

import datetime


class SiteConfiguration(SingletonModel):
    homepageText = MarkdownxField("Texte de la page d'accueil (Markdown)")
    writearticleText = MarkdownxField("Texte de la page « écrire » (Markdown)")
    email = CharField("Adresse de contact du BOcal",
                      max_length=128,
                      help_text="Attention au spam…")
    specialPublisDescr = MarkdownxField("Texte de la page des "
                                        "publications spéciales (Markdown)")

    def __str__(self):
        return "Configuration du site"

    class Meta:
        verbose_name = "Configuration du site"


class Publication(models.Model):
    num = CharField('Numéro du BOcal', max_length=128)
    url = CharField('Adresse sur le site', max_length=512)
    # ^ This is not a URLField because we need internal URLS, eg `/static/blah`

    date = DateField('Publication')
    is_special = BooleanField('Numéro spécial',
                              help_text='Numéro du BOcal non-numéroté',
                              default=False)
    in_year_view_anyway = BooleanField(
        "Aussi dans l'année",
        help_text=("Si le numéro est spécial, l'afficher quand même dans la "
                   "page de l'année correspondante."),
        default=False)
    descr = CharField('Description (optionnelle)',
                      max_length=512,
                      blank=True)
    custom_name = CharField('Nom customisé',
                            help_text='Vide pour laisser le numéro seulement',
                            max_length=128,
                            blank=True)

    class NoPublicationYear(Exception):
        def __str__(self):
            return "No matching publication year."

    @property
    def numericPublicationYear(self):
        startYear = self.date.year
        if self.date.month < 8:
            return startYear - 1
        return startYear

    def publicationYear(self):
        ''' Fetch corresponding publication year
        Raise `NoPublicationYear` if there is no such entry '''
        startYear = self.numericPublicationYear
        try:
            return PublicationYear.objects.get(startYear=startYear)
        except PublicationYear.DoesNotExist:
            raise self.NoPublicationYear

    def createPubYear(self):
        ''' Creates the corresponding publication year if needed. '''
        if (PublicationYear.objects
                .filter(startYear=self.numericPublicationYear).count()) == 0:
            pubYear = PublicationYear(startYear=self.numericPublicationYear,
                                      descr='')
            pubYear.save()
            return True
        return False

    def __str__(self):
        if self.custom_name:
            return self.custom_name
        elif self.is_special:
            return self.num
        return 'BOcal n°{}'.format(self.num)

    @staticmethod
    def latest():
        return Publication.objects.order_by('-date')[0]

    class Meta:
        ordering = ['date']


class PublicationYear(models.Model):
    startYear = IntegerField('Année de début',
                             help_text='Année scolaire à partir du 1/08',
                             primary_key=True)
    descr = MarkdownxField("Accroche de l'année (Markdown)")

    def __str__(self):
        return '{}-{}'.format(self.startYear, self.startYear+1)

    def beg(self):
        ''' First day of this publication year (incl.) '''
        return datetime.date(self.startYear, 8, 1)

    def end(self):
        ''' Last day of this publication year (excl.) '''
        return datetime.date(self.startYear + 1, 8, 1)

    def inYear(self, date):
        return self.beg() <= date < self.end()

    def publis(self):
        ''' List of publications from this year '''
        return Publication.objects.filter(
            Q(is_special=False) | Q(in_year_view_anyway=True),
            date__gte=self.beg(),
            date__lt=self.end())

    @property
    def url(self):
        return '/{}/'.format(self)

    @property
    def prettyName(self):
        return '{} – {}'.format(self.startYear, self.startYear+1)

    class Meta:
        ordering = ['-startYear']