from django.db.models import Avg, Count

from .models import Comment, Rating, Reaction
from .registry import ct


def summary(obj, user=None):
    ctype = ct(obj)
    where = {'content_type': ctype, 'object_id': obj.pk}
    counts = dict(Reaction.objects.filter(**where).values_list('kind').annotate(n=Count('id')))
    rating = Rating.objects.filter(**where).aggregate(avg=Avg('stars'), n=Count('id'))
    data = {
        'likes': counts.get('like', 0), 'saves': counts.get('save', 0),
        'rating_avg': round(rating['avg'] or 0, 1), 'rating_count': rating['n'],
        'comment_count': Comment.objects.filter(status='visible', **where).count(),
        'liked': False, 'saved': False, 'my_stars': 0,
    }
    if user is not None and user.is_authenticated:
        mine = set(Reaction.objects.filter(user=user, **where).values_list('kind', flat=True))
        data.update(liked='like' in mine, saved='save' in mine,
                    my_stars=Rating.objects.filter(user=user, **where).values_list('stars', flat=True).first() or 0)
    return data


def comments(obj, limit=50):
    return (Comment.objects.filter(content_type=ct(obj), object_id=obj.pk, status='visible')
            .select_related('user')[:limit])


def aggregate_rating_schema(obj, min_count=1):
    """schema.org AggregateRating dict, or None if too few ratings."""
    s = Rating.objects.filter(content_type=ct(obj), object_id=obj.pk).aggregate(avg=Avg('stars'), n=Count('id'))
    if not s['n'] or s['n'] < min_count:
        return None
    return {'@type': 'AggregateRating', 'ratingValue': round(s['avg'], 1), 'ratingCount': s['n'],
            'bestRating': 5, 'worstRating': 1}
