from django.apps import apps
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.http import require_POST, require_GET
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.shortcuts import render
import datetime
import django_comments
from django_comments import signals
from django_comments.views.utils import next_redirect, confirmation_view
from django_comments.views.comments import CommentPostBadRequest
from iconolab.models import MetaCategoryInfo, Annotation, IconolabComment
from iconolab.serializers import IconolabCommentSerializer
from rest_framework.renderers import JSONRenderer

@csrf_protect
@require_POST
def post_comment_iconolab(request, next=None, using=None):
    '''
    Rewriting of a django_comments method to link Iconolab metacategories on comment posting
    '''
    # Fill out some initial data fields from an authenticated user, if present
    data = request.POST.copy()
    if request.user.is_authenticated:
        if not data.get('name', ''):
            data['name'] = request.user.get_full_name() or request.user.get_username()
        if not data.get('email', ''):
            data['email'] = request.user.email

    # Look up the object we're trying to comment about
    ctype = data.get('content_type')
    object_pk = data.get('object_pk')
    if ctype is None or object_pk is None:
        return CommentPostBadRequest('Missing content_type or object_pk field.')
    try:
        model = apps.get_model(*ctype.split('.', 1))
        target = model._default_manager.using(using).get(pk=object_pk)
    except TypeError:
        return CommentPostBadRequest(
            'Invalid content_type value: %r' % escape(ctype))
    except AttributeError:
        return CommentPostBadRequest(
            'The given content-type %r does not resolve to a valid model.' % escape(ctype))
    except ObjectDoesNotExist:
        return CommentPostBadRequest(
            'No object matching content-type %r and object PK %r exists.' % (
                escape(ctype), escape(object_pk)))
    except (ValueError, ValidationError) as e:
        return CommentPostBadRequest(
            'Attempting go get content-type %r and object PK %r exists raised %s' % (
                escape(ctype), escape(object_pk), e.__class__.__name__))

    # Do we want to preview the comment?
    preview = 'preview' in data

    # Construct the comment form
    form = django_comments.get_form()(target, data=data)

    # Check security information
    if form.security_errors():
        return CommentPostBadRequest(
            'The comment form failed security verification: %s' % escape(str(form.security_errors())))

    # If there are errors or if we requested a preview show the comment
    if form.errors:
        return render(request, 'iconolab/detail_annotation.html', {
                'comment_form': form,
                'next': data.get('next', next),
                'annotation': target,
                'annotation_guid': target.annotation_guid,
                'image_guid': target.image.image_guid,
                'image': target.image,
                'collection_name': target.image.item.collection.name,
                'tags_data': target.current_revision.get_tags_json()
            },
        )

    # Otherwise create the comment
    comment = form.get_comment_object()
    comment.ip_address = request.META.get('REMOTE_ADDR', None)
    if request.user.is_authenticated:
        comment.user = request.user

    # Signal that the comment is about to be saved
    responses = signals.comment_will_be_posted.send(
        sender=comment.__class__,
        comment=comment,
        request=request
    )

    for (receiver, response) in responses:
        if response is False:
            return CommentPostBadRequest(
                'comment_will_be_posted receiver %r killed the comment' % receiver.__name__)

    # Save the comment and signal that it was saved
    comment.save()

    signals.comment_was_posted.send(
        sender=comment.__class__,
        comment=comment,
        request=request
    )

    # Creating metacategories here as apparently there is no way to make it work easily woth django_comments_xtd
    for metacategory in form.cleaned_data.get("metacategories", []):
        if 'xtd_comment' in comment:
            metacategory_info = MetaCategoryInfo.objects.create(
                comment = comment['xtd_comment'],
                metacategory = metacategory
            )

    return next_redirect(request, fallback=next or 'comments-comment-done',
                         c=comment._get_pk_val())

@require_GET
def get_comment_form(request, annotation_guid):
    # TODO Manage 404
    annotation = Annotation.objects.get(annotation_guid=annotation_guid)
    next_url = request.GET.get('next')
    form = django_comments.get_form()(annotation)

    metacategory_keys = {
        'Appel à contribution': 'request_for_contribution',
        'Référence': 'reference',
        'Accord': 'agree',
        'Désaccord': 'disagree'
    }
    metacategories = {}

    for metacategory in annotation.image.item.collection.metacategories.all():
        if metacategory.label not in metacategory_keys.keys():
            continue
        metacategories[metacategory_keys[metacategory.label]] = metacategory

    return render(request, 'partials/comment_form.html', {
        'comment_form': form,
        'metacategories': metacategories,
        'next': next_url
    })

@require_GET
def get_annotation_comments_json(request, annotation_guid):
    # TODO Manage 404
    annotation = Annotation.objects.get(annotation_guid=annotation_guid)
    comments = IconolabComment.objects.for_app_models('iconolab.annotation').filter(object_pk = annotation.pk).order_by('thread_id', '-order')
    serializer = IconolabCommentSerializer(comments, many=True)
    return HttpResponse(JSONRenderer().render(serializer.data), content_type="application/json")
