from django.template.loader import render_to_string
from django.db import models
from django.db.models import Count
from django.core.urlresolvers import reverse

from boards.models.base import Viewable
from boards.utils import cached_result
import boards

__author__ = 'neko259'


RELATED_TAGS_COUNT = 5


class TagManager(models.Manager):

    def get_not_empty_tags(self):
        """
        Gets tags that have non-archived threads.
        """

        return self.annotate(num_threads=Count('thread_tags')).filter(num_threads__gt=0)\
            .order_by('-required', 'name')

    def get_tag_url_list(self, tags: list) -> str:
        """
        Gets a comma-separated list of tag links.
        """

        return ', '.join([tag.get_view() for tag in tags])


class Tag(models.Model, Viewable):
    """
    A tag is a text node assigned to the thread. The tag serves as a board
    section. There can be multiple tags for each thread
    """

    objects = TagManager()

    class Meta:
        app_label = 'boards'
        ordering = ('name',)

    name = models.CharField(max_length=100, db_index=True, unique=True)
    required = models.BooleanField(default=False, db_index=True)
    description = models.TextField(blank=True)

    def __str__(self):
        return self.name

    def is_empty(self) -> bool:
        """
        Checks if the tag has some threads.
        """

        return self.get_thread_count() == 0

    def get_thread_count(self, archived=None) -> int:
        threads = self.get_threads()
        if archived is not None:
            threads = threads.filter(archived=archived)
        return threads.count()

    def get_active_thread_count(self) -> int:
        return self.get_thread_count(archived=False)

    def get_absolute_url(self):
        return reverse('tag', kwargs={'tag_name': self.name})

    def get_threads(self):
        return self.thread_tags.order_by('-bump_time')

    def is_required(self):
        return self.required

    def get_view(self):
        link = '<a class="tag" href="{}">{}</a>'.format(
            self.get_absolute_url(), self.name)
        if self.is_required():
            link = '<b>{}</b>'.format(link)
        return link

    def get_search_view(self, *args, **kwargs):
        return render_to_string('boards/tag.html', {
            'tag': self,
        })

    @cached_result()
    def get_post_count(self):
        return self.get_threads().aggregate(num_posts=Count('post'))['num_posts']

    def get_description(self):
        return self.description

    def get_random_image_post(self, archived=False):
        posts = boards.models.Post.objects.annotate(images_count=Count(
            'images')).filter(images_count__gt=0, threads__tags__in=[self])
        if archived is not None:
            posts = posts.filter(thread__archived=archived)
        return posts.order_by('?').first()

    def get_first_letter(self):
        return self.name and self.name[0] or ''

    def get_related_tags(self):
        return set(Tag.objects.filter(thread_tags__in=self.get_threads()).exclude(
                id=self.id).order_by('?')[:RELATED_TAGS_COUNT])