from django.utils.translation import ugettext as _
from django.db.models import F
from forum.models.action import ActionProxy, DummyActionProxy
from forum.models import Vote, Flag
from forum import settings

class VoteAction(ActionProxy):
    def update_node_score(self, inc):
        self.node.score = F('score') + inc
        self.node.save()

    def process_vote_action(self, value):
        self.update_node_score(value)
        vote = Vote(node=self.node, user=self.user, action=self, value=value)
        vote.save()

    def cancel_action(self):
        vote = self.vote
        self.update_node_score(-vote.value)
        vote.delete()

    @classmethod
    def get_for(cls, user, node):
        try:
            vote = Vote.objects.get(user=user, node=node)
            return vote.value
        except:
            return None

    @classmethod
    def get_action_for(cls, user, node):
        try:
            vote = Vote.objects.get(user=user, node=node)
            return vote.action
        except:
            return None

    def describe_vote(self, vote_desc, viewer=None):
        return _("%(user)s %(vote_desc)s %(post_desc)s") % {
            'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
            'vote_desc': vote_desc, 'post_desc': self.describe_node(viewer, self.node)
        }


class VoteUpAction(VoteAction):
    def repute_users(self):
        self.repute(self.node.author, int(settings.REP_GAIN_BY_UPVOTED))

    def process_action(self):
        self.process_vote_action(1)
        self.user.reset_vote_up_count_cache()

    def cancel_action(self):
        super(VoteUpAction, self).cancel_action()
        self.user.reset_vote_up_count_cache()

    def describe(self, viewer=None):
        return self.describe_vote(_("voted up"), viewer)

class VoteDownAction(VoteAction):
    def repute_users(self):
        self.repute(self.node.author, -int(settings.REP_LOST_BY_DOWNVOTED))
        self.repute(self.user, -int(settings.REP_LOST_BY_DOWNVOTING))

    def process_action(self):
        self.process_vote_action(-1)
        self.user.reset_vote_down_count_cache()

    def cancel_action(self):
        super(VoteDownAction, self).cancel_action()
        self.user.reset_vote_down_count_cache()

    def describe(self, viewer=None):
        return self.describe_vote(_("voted down"), viewer)


class VoteUpCommentAction(VoteUpAction):
    def repute_users(self):
        pass

    def process_action(self):
        self.process_vote_action(1)

    def cancel_action(self):
        super(VoteUpAction, self).cancel_action()

    def describe(self, viewer=None):
        return self.describe_vote(_("liked"), viewer)


class FlagAction(ActionProxy):
    def repute_users(self):
        self.repute(self.node.author, -int(settings.REP_LOST_BY_FLAGGED))

    def process_action(self):
        flag = Flag(user=self.user, node=self.node, action=self, reason=self.extra)
        flag.save()
        self.node.reset_flag_count_cache()

        if self.node.flag_count >= int(settings.FLAG_COUNT_TO_HIDE_POST):
            self.repute(self.node.author, -int(settings.REP_LOST_BY_FLAGGED_3_TIMES))

        if self.node.flag_count >= int(settings.FLAG_COUNT_TO_DELETE_POST):
            self.repute(self.node.author, -int(settings.REP_LOST_BY_FLAGGED_5_TIMES))
            if not self.node.nis.deleted:
                DeleteAction(node=self.node, user=self.user, extra="BYFLAGGED").save()

    def cancel_action(self):
        self.flag.delete()
        self.node.reset_flag_count_cache()

    @classmethod
    def get_for(cls, user, node):
        try:
            flag = Flag.objects.get(user=user, node=node)
            return flag.reason or _("No reason given")
        except:
            return None

    def describe(self, viewer=None):
        return _("%(user)s flagged %(post_desc)s: %(reason)s") % {
            'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
            'post_desc': self.describe_node(viewer, self.node), 'reason': self.extra
        }


class AcceptAnswerAction(ActionProxy):
    def repute_users(self):
        if (self.user == self.node.parent.author) and (not self.user == self.node.author):
            self.repute(self.user, int(settings.REP_GAIN_BY_ACCEPTING))

        if self.user != self.node.author:
            self.repute(self.node.author, int(settings.REP_GAIN_BY_ACCEPTED))

    def process_action(self):
        self.node.marked = True
        self.node.nstate.accepted = self
        self.node.save()
        self.node.question.reset_accepted_count_cache()

    def cancel_action(self):
        self.node.marked = False
        self.node.nstate.accepted = None
        self.node.save()
        self.node.question.reset_accepted_count_cache()

    def describe(self, viewer=None):
        answer = self.node
        question = answer.parent

        if self.user == question.author:
            asker = (self.user == viewer) and _("your") or _("his")
        else:
            asker = self.hyperlink(question.author.get_profile_url(), question.author.username)

        return _("%(user)s accepted %(answerer)s answer on %(asker)s question %(question)s") % {
            'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
            'answerer': self.hyperlink(answer.author.get_profile_url(), self.friendly_ownername(viewer, answer.author)),
            'asker': asker,
            'question': self.hyperlink(question.get_absolute_url(), question.title)
        }


class FavoriteAction(ActionProxy):
    def process_action(self):
        self.node.reset_favorite_count_cache()

    def cancel_action(self):
        self.process_action()

    def describe(self, viewer=None):
        return _("%(user)s marked %(post_desc)s as favorite") % {
            'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
            'post_desc': self.describe_node(viewer, self.node),
        }


class DeleteAction(ActionProxy):
    def process_action(self):
        self.node.mark_deleted(self)
        
        if self.node.node_type == "answer":
            self.node.question.reset_answer_count_cache()

    def cancel_action(self):
        self.node.mark_deleted(None)

        if self.node.node_type == "answer":
            self.node.question.reset_answer_count_cache()

    def describe(self, viewer=None):
        return _("%(user)s deleted %(post_desc)s") % {
            'user': self.hyperlink(self.user.get_profile_url(), self.friendly_username(viewer, self.user)),
            'post_desc': self.describe_node(viewer, self.node)
        }

    def reason(self):
        if self.extra != "BYFLAGGED":
            return self.extra
        else:
            return _("flagged by multiple users: ") + "; ".join([f.extra for f in FlagAction.objects.filter(node=self.node)])

class UnknownAction(ActionProxy):
    pass


class QuestionViewAction(DummyActionProxy):
    def __init__(self, node, user, ip=None):
        self.viewuser = user
        self.node = node
        super(QuestionViewAction, self).__init__(ip)

    def process_action(self):
        self.node.extra_count = F('extra_count') + 1
        self.node.save()
