# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from odoo import api, fields, models, _
from odoo.exceptions import UserError, AccessError


class Vote(models.Model):
    _name = 'forum.post.vote'
    _description = 'Post Vote'
    _order = 'create_date desc, id desc'

    post_id = fields.Many2one('forum.post', string='Post', ondelete='cascade', required=True)
    user_id = fields.Many2one('res.users', string='User', required=True, default=lambda self: self._uid, ondelete='cascade')
    vote = fields.Selection([('1', '1'), ('-1', '-1'), ('0', '0')], string='Vote', required=True, default='1')
    create_date = fields.Datetime('Create Date', index=True, readonly=True)
    forum_id = fields.Many2one('forum.forum', string='Forum', related="post_id.forum_id", store=True, readonly=False)
    recipient_id = fields.Many2one('res.users', string='To', related="post_id.create_uid", store=True, readonly=False)

    _sql_constraints = [
        ('vote_uniq', 'unique (post_id, user_id)', "Vote already exists!"),
    ]

    def _get_karma_value(self, old_vote, new_vote, up_karma, down_karma):
        """Return the karma to add / remove based on the old vote and on the new vote."""
        karma_values = {'-1': down_karma, '0': 0, '1': up_karma}
        karma = karma_values[new_vote] - karma_values[old_vote]

        if old_vote == new_vote:
            reason = _('no changes')
        elif new_vote == '1':
            reason = _('upvoted')
        elif new_vote == '-1':
            reason = _('downvoted')
        elif old_vote == '1':
            reason = _('no more upvoted')
        else:
            reason = _('no more downvoted')

        return karma, reason

    @api.model_create_multi
    def create(self, vals_list):
        # can't modify owner of a vote
        if not self.env.is_admin():
            for vals in vals_list:
                vals.pop('user_id', None)

        votes = super(Vote, self).create(vals_list)

        for vote in votes:
            vote._check_general_rights()
            vote._check_karma_rights(vote.vote == '1')

            # karma update
            vote._vote_update_karma('0', vote.vote)
        return votes

    def write(self, values):
        # can't modify owner of a vote
        if not self.env.is_admin():
            values.pop('user_id', None)

        for vote in self:
            vote._check_general_rights(values)
            vote_value = values.get('vote')
            if vote_value is not None:
                upvote = vote.vote == '-1' if vote_value == '0' else vote_value == '1'
                vote._check_karma_rights(upvote)

                # karma update
                vote._vote_update_karma(vote.vote, vote_value)

        res = super(Vote, self).write(values)
        return res

    def _check_general_rights(self, vals=None):
        if vals is None:
            vals = {}
        post = self.post_id
        if vals.get('post_id'):
            post = self.env['forum.post'].browse(vals.get('post_id'))
        if not self.env.is_admin():
            # own post check
            if self._uid == post.create_uid.id:
                raise UserError(_('It is not allowed to vote for its own post.'))
            # own vote check
            if self._uid != self.user_id.id:
                raise UserError(_('It is not allowed to modify someone else\'s vote.'))

    def _check_karma_rights(self, upvote=False):
        # karma check
        if upvote and not self.post_id.can_upvote:
            raise AccessError(_('%d karma required to upvote.', self.post_id.forum_id.karma_upvote))
        elif not upvote and not self.post_id.can_downvote:
            raise AccessError(_('%d karma required to downvote.', self.post_id.forum_id.karma_downvote))

    def _vote_update_karma(self, old_vote, new_vote):
        if self.post_id.parent_id:
            karma, reason = self._get_karma_value(
                old_vote,
                new_vote,
                self.forum_id.karma_gen_answer_upvote,
                self.forum_id.karma_gen_answer_downvote)
            source = _('Answer %s', reason)
        else:
            karma, reason = self._get_karma_value(
                old_vote,
                new_vote,
                self.forum_id.karma_gen_question_upvote,
                self.forum_id.karma_gen_question_downvote)
            source = _('Question %s', reason)
        self.recipient_id.sudo()._add_karma(karma, self.post_id, source)
