<?php

namespace Mnv\Models;

use Mnv\Core\Model;
use Mnv\Http\Request;

/**
 * Class Comments
 * @package Mnv\Models
 */
class Reviews extends Model
{
    /** @var string */
    protected string $table = 'product_comments';

    /** @var string  */
    protected string $primaryKey = 'commentId';

    /** @var string  */
    protected string $orderBy = '';

    /** @var  */
    public $bulk;


    public function __construct(Request $request)
    {
        $this->id   = $request->get('id');                 //   getRequestVar('id', ''),
        $this->data = $request->get('comment', ''); //   getRequestVar('comment','', true)
        $this->bulk = $request->get('bulk','');     //   getRequestVar('bulk','', true)
    }

    private function sorting()
    {
        /* processing search fields */
        if (!empty($this->filter['query'])) {
            connect()->grouped(function($q) {
                $q->like('content', "%" . $this->filter['query'] . "%")
                    ->orLike('authorName', "%" . $this->filter['query'] . "%")
                    ->orLike('authorEmail',"%" . $this->filter['query']. "%");
            });
        }

        if (!empty($this->filter['status'])) {
            connect()->where('status',  $this->filter['status']);
            if ($this->filter['status'] === 'pending') {
                connect()->orderBy('addedOn', 'ASC');
            } else {
                connect()->orderBy('addedOn', 'DESC');
            }
        } else {
            connect()->in('status', ['pending', 'approved']);
            connect()->orderBy('addedOn', 'DESC');
        }

        if (!empty($this->filter['dateStart']) && !empty($this->filter['dateEnd'])) {
            connect()->between('addedOn', $this->filter['dateStart'], $this->filter['dateEnd']);
        }
    }


    public function all($limit, $page)
    {
        $this->sorting();

        return parent::all($limit, $page);
    }


    public function total()
    {
        $this->sorting();

        parent::total();
    }

    public function prepare(array $data, int $managerId): bool
    {

        if (!empty($this->id)) {

            $data['modifiedBy'] = $managerId;
            $data['modifiedOn'] = gmdate('Y-m-d H:i:s');

            if ($this->update($data)) {
                /**  получение productId @var  $productId */
                $productId = $this->getProductId($this->id);
                /** Получение кол-ва комментариев @var $totalComments */
                $totalComments = $this->totalComments($productId);
                /** обновление кол-ва комментариев у контента по его productId */
                $this->updateArticleTotalComments($productId, $totalComments);
                /** votes $article->votes */
                if ($data['status'] == 'approved') {
                    $this->setRating($productId, $data['rating'], $this->id);
                }
//                if ($comment['status'] == 'approved' && $comment['checkRating'] == 0) {
//                    $this->setRating($productId, $comment['rating'], $this->commentId);
//                }

                return true;
            }

        }
        return false;

    }


    /**
     * Обновление рейтинга у контента
     *
     * TODO: продумать что при сохранение не дублировать данные
     * @param $productId
     * @param $rating
     * @param $commentId
     */
    private function setRating($productId, $rating, $commentId)
    {
        $product = connect('products')->select('productId, rating, votes')->where('productId', $productId)->get('array');
        if ($product) {
            $product['rating'] = number_format(($product['rating'] * $product['votes'] + $rating) / ($product['votes'] + 1), 1, '.', ',');
            $product['votes'] = $product['votes'] + 1;
            connect('products')->where('productId', $product['productId'])->update(['rating' => $product['rating'], 'votes' => $product['votes']]);
            connect($this->table)->where($this->primaryKey, $commentId)->update(['checkRating' => 1]);
        }
    }

    /**
     * получение productId
     * @param $commentId
     * @return mixed
     */
    private function getProductId($commentId)
    {
        return connect($this->table)->select('productId')->where($this->primaryKey,  $commentId)->getValue();
    }

    /**
     * Получение кол-ва комментариев
     * @param $productId
     * @return array|false|mixed|string
     */
    private function totalComments($productId) {
        return connect($this->table)->count('*', 'count')->where('productId', $productId)->where('status', 'approved')->getValue();
    }


    /**
     * обновление кол-ва комментариев у статьи
     * @param $productId
     * @param $totalComments
     */
    private function updateArticleTotalComments($productId, $totalComments)
    {
        connect('products')->where('productId', $productId)->update(['totalComments' => $totalComments]);
    }

    /**
     * @param $bulk
     * @return bool
     */
    public function bulk($bulk): bool
    {
        if (!empty($bulk)) {
            $productIds = connect($this->table)->select('DISTINCT productId')->in($this->primaryKey, array_keys($bulk))->indexKey('productId')->getAllIndexes();

            foreach ($bulk as $commentId => $commentStatus) {
                if ($commentStatus == 1) {
                    connect()->table($this->table)->where($this->primaryKey, $commentId)->update(['status' => 'approved']);
                } elseif ($commentStatus == 2) {
                    connect()->table($this->table)->where($this->primaryKey, $commentId)->update(['status' => 'spam']);
                } elseif ($commentStatus == 3) {
                    connect()->table($this->table)->where($this->primaryKey, $commentId)->delete();
                } elseif ($commentStatus == 0) {
                    connect()->table($this->table)->where($this->primaryKey, $commentId)->update(['status' => 'pending']);
                }
            }

            /* update totalComments */
//            $commentTotals = dbQuery('comments', DB_ARRAYS, array('where'=>"productId IN('".implode("','", $productIds)."') AND status='approved'", 'fields'=>'productId, COUNT(*) AS totalComments', 'group'=>'productId', 'indexKey'=>'productId', 'valueKey'=>'totalComments'));
//            foreach($commentTotals as $productId=>$totalComments) dbQuery('articles', DB_UPDATE, array('where'=>"productId='$productId'", 'values'=>"totalComments='$totalComments'"));
            // 'indexKey'=>'productId', 'valueKey'=>'totalComments'

            $commentTotals = connect($this->table)->select('productId, COUNT(*) AS totalComments')->in('productId', array_keys($productIds))
                ->where('status','approved')->groupBy('productId')
                ->indexKey('productId')
                ->valueKey('totalComments')
                ->getAllIndexes('array');

//            print_r($commentTotals);
            /** TODO: Выдает ошибку по $productId так как его нет  */
            foreach($commentTotals as $productId => $totalComments) {
                connect()->table('products')->where('productId', $productId)->update(['totalComments' => $totalComments]);
            }
            return true;
        }
        return false;
    }


    /**
     * получение комментариев ожидающих подтверждение
     *
     * @return array|false|mixed|string
     */
    public static function getPendingComments()
    {
        $comments =  connect('product_comments')->where('status','pending')->getAll('array');
        foreach ($comments as $commentId => $comment) {
            $comments[$commentId]['addedOn'] = adjustTime($comment['addedOn'], false, 'd.m.Y H:i');
        }

        return $comments;
    }

    /**
     * получение кол-во комментариев ожидающих подтверждение
     *
     * @return mixed|string|null
     */
    public static function totalPendingComments()
    {
        return connect('product_comments')->where('status', 'pending')->count('*', 'count')->getValue();
    }

}