from django.db import models
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _

from pulseapi.utility.validators import YearValidator


class ProfileType(models.Model):
    """
    See https://github.com/mozilla/network-pulse/issues/657

    Values that should exist (handled via migration):

    - plain
    - staff
    - fellow
    - board member
    - grantee
    """
    value = models.CharField(
        max_length=50,
        unique=True
    )

    def get_default_profile_type():
        (default, _) = ProfileType.objects.get_or_create(value='plain')
        return default

    def __str__(self):
        return self.value


class ProgramType(models.Model):
    """
    See https://github.com/mozilla/network-pulse/issues/657

    These values are determined by pulse API administrators
    (tech policy fellowship, mozfest speaker, etc)
    """
    value = models.CharField(
        max_length=150,
        unique=True
    )

    def __str__(self):
        return self.value


class ProgramYear(models.Model):
    """
    See https://github.com/mozilla/network-pulse/issues/657

    You'd think this would be 4 characters, but a "year" is
    not a calendar year, so the year could just as easily
    be "summer 2017" or "Q2 2016 - Q1 2018", so this is the
    same kind of simple value model that the profile and
    program types use.
    """
    value = models.CharField(
        max_length=25,
        unique=True
    )

    def __str__(self):
        return self.value


class CohortRecord(models.Model):
    profile = models.ForeignKey(
        'profiles.UserProfile',
        on_delete=models.CASCADE,
        related_name='cohort_records',
    )

    program = models.ForeignKey(
        'profiles.ProgramType',
        on_delete=models.PROTECT,
        related_name='profile_cohort_records',
    )

    year = models.PositiveSmallIntegerField(
        # TODO: Change to MaxValueValidator with callable when
        #       we update to Django > v2.2
        validators=[YearValidator(max_offset=2)],
        null=True,
        blank=True,
    )

    cohort_name = models.CharField(
        null=True,
        blank=True,
        max_length=200,
    )

    def __str__(self):
        return f'{self.profile.name} - {self.program} {str(self.year)} {self.cohort_name}'

    def clean(self):
        super().clean()

        # Don't allow both the cohort and year to be empty
        if self.year is None and not self.cohort_name:
            raise ValidationError(
                _('Either the year or cohort must have a value')
            )

    def save(self, *args, **kwargs):
        self.full_clean()
        super().save(*args, **kwargs)

    class Meta:
        verbose_name = 'cohort record'
        # This meta option creates an _order column in the table
        # See https://docs.djangoproject.com/en/1.11/ref/models/options/#order-with-respect-to for more details
        order_with_respect_to = 'profile'
        # We prefix the index name in the database with uk to indicate that the constraint is a unique key
        indexes = [
            models.Index(fields=['profile', '_order'], name='uk_membership_profile_order'),
        ]


class ProfileRole(models.Model):
    profile = models.ForeignKey(
        'profiles.UserProfile',
        on_delete=models.CASCADE,
        related_name='related_types',
    )

    profile_type = models.ForeignKey(
        'profiles.ProfileType',
        on_delete=models.CASCADE,
        related_name='related_profiles',
    )

    is_current = models.BooleanField(default=True)

    def __str__(self):
        copular_verb = 'is' if self.is_current else 'was'
        return f'{self.profile.name} {copular_verb} a {self.role}'

    class Meta:
        # This meta option creates an _order column in the table
        # See https://docs.djangoproject.com/en/1.11/ref/models/options/#order-with-respect-to for more details
        order_with_respect_to = 'profile'
        # We prefix the index name in the database with uk to indicate that the constraint is a unique key
        indexes = [
            models.Index(fields=['profile', 'is_current', '_order'], name='uk_role_profile_current_order'),
            models.Index(fields=['profile', 'is_current', 'profile_type'], name='uk_role_profile_current_type'),
        ]
