import bleach

from rest_framework import serializers as ser
from modularodm import Q
from osf.exceptions import ValidationError as ModelValidationError
from framework.auth.core import Auth
from framework.exceptions import PermissionsError
from framework.guid.model import Guid
from website.files.models import StoredFileNode
from website.project.model import Comment
from rest_framework.exceptions import ValidationError, PermissionDenied
from api.base.exceptions import InvalidModelValueError, Conflict
from api.base.utils import absolute_reverse
from api.base.settings import osf_settings
from api.base.serializers import (JSONAPISerializer,
                                  TargetField,
                                  RelationshipField,
                                  IDField, TypeField, LinksField,
                                  AuthorizedCharField, DateByVersion,)
from website.project.spam.model import SpamStatus


class CommentReport(object):
    def __init__(self, user_id, category, text):
        self._id = user_id
        self.category = category
        self.text = text


class CommentSerializer(JSONAPISerializer):

    filterable_fields = frozenset([
        'deleted',
        'date_created',
        'date_modified',
        'page',
        'target'
    ])

    id = IDField(source='_id', read_only=True)
    type = TypeField()
    content = AuthorizedCharField(source='get_content', required=True)
    page = ser.CharField(read_only=True)

    target = TargetField(link_type='related', meta={'type': 'get_target_type'})
    user = RelationshipField(related_view='users:user-detail', related_view_kwargs={'user_id': '<user._id>'})
    reports = RelationshipField(related_view='comments:comment-reports', related_view_kwargs={'comment_id': '<_id>'})

    date_created = DateByVersion(read_only=True)
    date_modified = DateByVersion(read_only=True)
    modified = ser.BooleanField(read_only=True, default=False)
    deleted = ser.BooleanField(read_only=True, source='is_deleted', default=False)
    is_abuse = ser.SerializerMethodField(help_text='If the comment has been reported or confirmed.')
    is_ham = ser.SerializerMethodField(help_text='Comment has been confirmed as ham.')
    has_report = ser.SerializerMethodField(help_text='If the user reported this comment.')
    has_children = ser.SerializerMethodField(help_text='Whether this comment has any replies.')
    can_edit = ser.SerializerMethodField(help_text='Whether the current user can edit this comment.')

    # LinksField.to_representation adds link to "self"
    links = LinksField({})

    class Meta:
        type_ = 'comments'

    def get_is_ham(self, obj):
        if obj.spam_status == SpamStatus.HAM:
            return True
        return False

    def get_has_report(self, obj):
        user = self.context['request'].user
        if user.is_anonymous():
            return False
        return user._id in obj.reports and not obj.reports[user._id].get('retracted', True)

    def get_is_abuse(self, obj):
        if obj.spam_status == SpamStatus.FLAGGED or obj.spam_status == SpamStatus.SPAM:
            return True
        return False

    def get_can_edit(self, obj):
        user = self.context['request'].user
        if user.is_anonymous():
            return False
        return obj.user._id == user._id and obj.node.can_comment(Auth(user))

    def get_has_children(self, obj):
        return Comment.find(Q('target', 'eq', Guid.load(obj._id))).count() > 0

    def get_absolute_url(self, obj):
        return absolute_reverse('comments:comment-detail', kwargs={
            'comment_id': obj._id,
            'version': self.context['request'].parser_context['kwargs']['version']
        })

    def update(self, comment, validated_data):
        assert isinstance(comment, Comment), 'comment must be a Comment'
        auth = Auth(self.context['request'].user)

        if validated_data:
            if validated_data.get('is_deleted', None) is False and comment.is_deleted: