"""Likes, saves, star ratings and comments for articles, magazine issues and games.
Signed-in readers only. One generic set of tables so new content types can join later."""
from django.conf import settings
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models


class _Target(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    target = GenericForeignKey('content_type', 'object_id')
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        abstract = True


class Reaction(_Target):
    KINDS = (('like', 'Like'), ('save', 'Save'))
    kind = models.CharField(max_length=8, choices=KINDS)

    class Meta:
        constraints = [models.UniqueConstraint(fields=['user', 'content_type', 'object_id', 'kind'], name='one_reaction_each')]
        indexes = [models.Index(fields=['content_type', 'object_id', 'kind'])]
        ordering = ['-created_at']

    def __str__(self):
        return f'{self.user} {self.kind}d {self.target}'


class Rating(_Target):
    stars = models.PositiveSmallIntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)])
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        constraints = [models.UniqueConstraint(fields=['user', 'content_type', 'object_id'], name='one_rating_each')]
        indexes = [models.Index(fields=['content_type', 'object_id'])]
        ordering = ['-updated_at']

    def __str__(self):
        return f'{self.stars}★ by {self.user} on {self.target}'


class Comment(_Target):
    STATUS = (('visible', 'Visible'), ('pending', 'Waiting for review'), ('hidden', 'Hidden'))
    body = models.TextField(max_length=1500)
    status = models.CharField(max_length=8, choices=STATUS, default='visible', db_index=True)

    class Meta:
        indexes = [models.Index(fields=['content_type', 'object_id', 'status'])]
        ordering = ['-created_at']

    def __str__(self):
        return f'{self.user}: {self.body[:40]}'

    @property
    def author_name(self):
        u = self.user
        return u.get_full_name() or (u.email.split('@')[0] if u.email else u.username)
