<?php
/**
 * @property \modelRating $model
 */
class actionRatingVote extends cmsAction {

    public function run() {

        if (!$this->request->isAjax()) {
            return cmsCore::error404();
        }

        // включено ли голосование от гостей?
        if (empty($this->options['allow_guest_vote']) && !$this->cms_user->is_logged) {

            return $this->cms_template->renderJSON([
                'success' => false,
                'message' => LANG_ERROR
            ]);
        }

        // Получаем параметры
        $direction         = $this->request->get('direction', '');
        $target_controller = $this->request->get('controller', '');
        $target_subject    = $this->request->get('subject', '');
        $target_id         = $this->request->get('id', 0);
        $score             = $this->request->get('score', 0);

        $is_valid = ($this->validate_sysname($target_controller) === true) &&
                ($this->validate_sysname($target_subject) === true) &&
                is_numeric($target_id) &&
                (
                ($direction && in_array($direction, ['up', 'down'])) ||
                ($score && is_numeric($score))
                );

        if (!$is_valid) {

            return $this->cms_template->renderJSON([
                'success' => false,
                'message' => LANG_ERROR
            ]);
        }

        // Проверяем наличие контроллера и модели
        if (!(cmsCore::isControllerExists($target_controller) &&
                cmsCore::isModelExists($target_controller) &&
                cmsController::enabled($target_controller))) {

            return $this->cms_template->renderJSON([
                'success' => false,
                'message' => LANG_ERROR
            ]);
        }

        // получаем контроллер цели
        $controller = cmsCore::getController($target_controller, $this->request);

        // флаг, что рейтинг считать как среднее арифметическое
        $average_rating = true;

        // приоритет за $score
        if (!$score) {

            $score = ($direction === 'up' ? 1 : -1);

            $average_rating = false;

        } else {

            // Проверяем флаг, что рейтинг считаем как среднее арифметическое
            if (method_exists($controller, 'isAverageRating')) {
                $average_rating = $controller->isAverageRating($target_subject, $target_id, $score);
            }

            // валидация оценки
            if (method_exists($controller, 'validate_rating_score') && !$controller->validate_rating_score($score)) {

                return $this->cms_template->renderJSON([
                    'success' => false,
                    'message' => LANG_ERROR
                ]);
            }
        }

        // Объединяем всю информацию о голосе
        $vote = [
            'user_id'           => ($this->cms_user->id ? $this->cms_user->id : null),
            'target_controller' => $target_controller,
            'target_subject'    => $target_subject,
            'target_id'         => $target_id,
            'score'             => $score,
            'ip'                => $this->cms_user->ip
        ];

        $target = $controller->model->getRatingTarget($target_subject, $target_id);

        if (!$target) {

            return $this->cms_template->renderJSON([
                'success' => false,
                'message' => LANG_ERROR
            ]);
        }

        $cookie_key = $target_subject . $target_id . $target_controller;

        // Этот голос уже учитывался?
        $is_voted = $this->model->isUserVoted($vote, $this->cms_user->is_logged);
        if ($is_voted) {

            // если куки нет, ставим
            if (!empty($this->options['is_hidden']) && !cmsUser::getCookie($cookie_key)) {
                cmsUser::setCookie($cookie_key, 1, 2628000); // год
            }

            return $this->cms_template->renderJSON([
                'success'   => false,
                'rating'    => html_signed_num($target['rating']),
                'css_class' => html_signed_class($target['rating']) . ($this->options['is_show'] ? ' clickable' : ''),
                'message'   => LANG_RATING_VOTED
            ]);
        }

        if (!empty($target['user_id'])) {
            if ($this->cms_user->is_logged) {
                if ($target['user_id'] == $this->cms_user->id || !cmsUser::isAllowed($target_subject, 'rate')) {

                    return $this->cms_template->renderJSON([
                        'success' => false,
                        'message' => LANG_RATING_DISABLED
                    ]);
                }
            }
        }

        // Добавляем голос в лог
        $this->model->addVote($vote);

        // как считать суммарный рейтинг
        if ($average_rating) {
            $rating = round($this->model->getTargetAverageRating($vote), 0, PHP_ROUND_HALF_DOWN);
        } else {
            $rating = intval($target['rating'] + $vote['score']);
        }

        // Обновляем суммарный рейтинг цели
        $controller->model->updateRating($target_subject, $target_id, $rating);

        // Оповещаем всех об изменении рейтинга
        cmsEventsManager::hook('rating_vote', [
            'subject' => $target_subject,
            'id'      => $target_id,
            'target'  => $target,
            'vote'    => $vote,
            'rating'  => $rating
        ]);

        // ссылка на проголосовавшего
        if ($this->cms_user->is_logged) {
            $user_link = '<a href="' . href_to_profile($this->cms_user) . '">' . $this->cms_user->nickname . '</a>';
        } else {
            $user_link = LANG_GUEST;
        }

        // уведомляем автора записи
        $this->controller_messages->addRecipient($target['user_id'])->sendNoticePM([
            'content' => sprintf(LANG_RATING_PM,
            $user_link,
            $direction ? string_lang('LANG_RATING_' . $direction) : '',
            $target['page_url'],
            $target['title'])
        ], 'rating_user_vote');

        // Собираем результат
        $result = [
            'success'      => true,
            'rating_value' => $rating,
            'show_info'    => !empty($this->options['is_show']),
            'rating'       => html_signed_num($rating),
            'css_class'    => html_signed_class($rating) . ($this->options['is_show'] ? ' clickable' : ''),
            'message'      => LANG_RATING_VOTED
        ];

        // запоминаем в куках
        if (!empty($this->options['is_hidden'])) {
            cmsUser::setCookie($cookie_key, 1, 2628000); // год
        }

        return $this->cms_template->renderJSON($result);
    }

}
