from django.core.urlresolvers import reverse
from django.db import transaction
from django.http import Http404
from django.shortcuts import get_object_or_404, render, redirect
from django.views.generic.edit import FormMixin

from boards import utils, settings
from boards.forms import PostForm, PlainErrorList
from boards.models import Post, Ban
from boards.views.banned import BannedView
from boards.views.base import BaseBoardView, CONTEXT_FORM
from boards.views.posting_mixin import PostMixin

TEMPLATE_GALLERY = 'boards/thread_gallery.html'
TEMPLATE_NORMAL = 'boards/thread.html'

CONTEXT_POSTS = 'posts'
CONTEXT_OP = 'opening_post'
CONTEXT_BUMPLIMIT_PRG = 'bumplimit_progress'
CONTEXT_POSTS_LEFT = 'posts_left'
CONTEXT_LASTUPDATE = "last_update"
CONTEXT_MAX_REPLIES = 'max_replies'
CONTEXT_THREAD = 'thread'
CONTEXT_BUMPABLE = 'bumpable'

FORM_TITLE = 'title'
FORM_TEXT = 'text'
FORM_IMAGE = 'image'

MODE_GALLERY = 'gallery'
MODE_NORMAL = 'normal'


class ThreadView(BaseBoardView, PostMixin, FormMixin):

    def get(self, request, post_id, mode=MODE_NORMAL, form=None):
        try:
            opening_post = Post.objects.filter(id=post_id).only('thread_new')[0]
        except IndexError:
            raise Http404

        # If this is not OP, don't show it as it is
        if not opening_post or not opening_post.is_opening():
            raise Http404

        if not form:
            form = PostForm(error_class=PlainErrorList)

        thread_to_show = opening_post.get_thread()

        context = self.get_context_data(request=request)

        context[CONTEXT_FORM] = form
        context[CONTEXT_LASTUPDATE] = utils.datetime_to_epoch(
            thread_to_show.last_edit_time)
        context[CONTEXT_THREAD] = thread_to_show
        context[CONTEXT_MAX_REPLIES] = settings.MAX_POSTS_PER_THREAD

        if MODE_NORMAL == mode:
            bumpable = thread_to_show.can_bump()
            context[CONTEXT_BUMPABLE] = bumpable
            if bumpable:
                left_posts = settings.MAX_POSTS_PER_THREAD \
                             - thread_to_show.get_reply_count()
                context[CONTEXT_POSTS_LEFT] = left_posts
                context[CONTEXT_BUMPLIMIT_PRG] = str(
                    float(left_posts) / settings.MAX_POSTS_PER_THREAD * 100)

            context[CONTEXT_OP] = opening_post

            document = TEMPLATE_NORMAL
        elif MODE_GALLERY == mode:
            context[CONTEXT_POSTS] = thread_to_show.get_replies_with_images(
                view_fields_only=True)

            document = TEMPLATE_GALLERY
        else:
            raise Http404

        return render(request, document, context)

    def post(self, request, post_id, mode=MODE_NORMAL):
        opening_post = get_object_or_404(Post, id=post_id)

        # If this is not OP, don't show it as it is
        if not opening_post.is_opening():
            raise Http404

        if not opening_post.get_thread().archived:
            form = PostForm(request.POST, request.FILES,
                            error_class=PlainErrorList)
            form.session = request.session

            if form.is_valid():
                return self.new_post(request, form, opening_post)
            if form.need_to_ban:
                # Ban user because he is suspected to be a bot
                self._ban_current_user(request)

            return self.get(request, post_id, mode, form)

    @transaction.atomic
    def new_post(self, request, form, opening_post=None, html_response=True):
        """Add a new post (in thread or as a reply)."""

        ip = utils.get_client_ip(request)
        is_banned = Ban.objects.filter(ip=ip).exists()

        if is_banned:
            if html_response:
                return redirect(BannedView().as_view())
            else:
                return None

        data = form.cleaned_data

        title = data[FORM_TITLE]
        text = data[FORM_TEXT]

        text = self._remove_invalid_links(text)

        if FORM_IMAGE in list(data.keys()):
            image = data[FORM_IMAGE]
        else:
            image = None

        tags = []

        post_thread = opening_post.get_thread()

        post = Post.objects.create_post(title=title, text=text, image=image,
                                        thread=post_thread, ip=ip, tags=tags)

        thread_to_show = (opening_post.id if opening_post else post.id)

        if html_response:
            if opening_post:
                return redirect(
                    reverse('thread', kwargs={'post_id': thread_to_show})
                    + '#' + str(post.id))
        else:
            return post