<?php
/**
 * Copyright (c) 2016 Serhii Borodai <clarifying@gmail.com>.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 *
 */

namespace App\Action\User;


use App\Action\Common;
use App\Authentication\UserService;
use App\Model\Users;
use App\Model\Statistics;
use App\Model\Providers;
use App\Model\Feeds\Feeds;
use App\Model\Feeds\OrdersStatus;
use App\Entity\Feeds\CategoryFee;
use App\Entity\Feeds\OrderStatus;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Diactoros\Response\HtmlResponse;
use Zend\Diactoros\Response\JsonResponse;
use Zend\Diactoros\Response\RedirectResponse;
use Zend\Hydrator\DelegatingHydrator;


/**
 * Class Cabinet
 * @package App\Action\User
 */
class Cabinet extends Common
{
    const ACTION_STAT = 'stat';
    const ACTION_CATS = 'cats';

    /**
     * @param ServerRequestInterface $request
     * @param ResponseInterface $response
     * @param callable|null $next
     * @return HtmlResponse
     */
    function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next = null)
    {  
        
        /** @var \App\Model\Statistics $stats */
        $stats = $this->container->get(Statistics::class);
        
        if($request->getMethod() == 'POST') {
            
            try {
                switch ($request->getAttribute('action')) {
                    case self::ACTION_STAT:
                        $response = $this->getStatData($request);
                        break;
                    case self::ACTION_CATS:
                        $response = $this->editCatsData($request);
                        break;
                    default:
                }
            } catch(\Exception $e) {
                $data = [
                    'result' => false,
                    'msg' => $e->getMessage(),
                ];
                $response = new JsonResponse($data);
            }
            return $response;
            
        }
        elseif($request->getAttribute('action') == self::ACTION_STAT)
        {
            
            try {

                /** @var UserService $auth */
                $auth = $this->container->get(UserService::class);
                $userId = $auth->getIdentity()->getId();

                /** @var \App\Model\Feeds\Shops $shopsModel */
                $shopsModel = $this->container->get(\App\Model\Feeds\Shops::class);
                $shop = $shopsModel->findOne(['users_id' => $userId]);
                if($shop) {
                    $shop_title = $shop->getTitle();
                }
                
                /** @var \App\Model\Feeds $feedsModel */
                $feedsModel = $this->container->get(Feeds::class);
                $feeds = $feedsModel->findAll(['clientid' => $userId])->toArray();
                
                if ($feeds) {
                    
                    // Фиды пользователя:
                    $feed_id_list = [];
                    foreach($feeds as $feed_item) {
                        $feed_id = $feed_item['id'];
                        if (!in_array($feed_id, $feed_id_list)) {
                            $feed_id_list[] = $feed_id;
                        }
                    }

                    $report_type = $request->getAttribute('report');

                    // Текущий месяц:
                    $current_period = 'current_month';
                    $dates = [date('Y-m-01'), date('Y-m-d')];

                    $reports_conf = $this->container->get('config')['feed_conf']['reports'];
                    $report_conf = $reports_conf[$report_type];
                    
                    // Список отчетов:
                    $reports_list = [];
                    foreach($reports_conf as $report_name => $report_value) {
                        $reports_list[$report_name] = $report_value['title'];
                    }
                    
                    switch ($report_type) {
                        case 'common':
                            $periodStats = $stats->getFeedStatData($report_type, $feed_id_list, $dates, $report_conf);
                            break;
                        case 'transactions':
                            $periodStats = $stats->getFeedStatData($report_type, $feed_id_list, $dates, $report_conf);
                            break;
                        default:
                            $data['error'] = _t('Извините, тип отчета "'. $report_type .'" недоступен');
                            break;
                    }
                    
                    // Добавляем спец. категории для сводного отчета по магазину:
                    if ($report_type == 'common') {
                        $periodStats = $this->addStatsSpecialCats($periodStats);
                    }
                    
                    // Добавляем данные о статусах заказов:
                    if ($report_type == 'transactions') {
                        if ($periodStats) {
                            /** @var \App\Model\Feeds $ordersStatusModel */
                            $ordersStatusModel = $this->container->get(OrdersStatus::class);
                            $ordersStatus = $ordersStatusModel->findAll(['feed_id' => $feed_id_list])->toArray();
                            $statuses = [];
                            foreach($ordersStatus as $order_item) {
                                $statuses[$order_item['feed_id']][$order_item['order_id']] = array(
                                    'confirmed' => $order_item['confirmed'] ? 1 : 0,
                                    'approved' => $order_item['approved'] ? 1 : 0
                                );
                            }
                            $periodStats['ordersStatus'] = $statuses;
                        }
                    }
                    
                    $data['shop_title'] = $shop_title;
                    $data['feeds'] = $feeds;
                    $data['current_report'] = $report_type;
                    $data['current_period'] = $current_period;
                    $data['dates'] = $dates;
                    $data['periodStats'] = $periodStats;
                    $data['report_conf'] = $report_conf;
                    $data['reports_list'] = $reports_list;
                    $data['periods_list'] = $this->container->get('config')['feed_conf']['periods_list'];
                    $data['colors_active_lines'] = $this->container->get('config')['feed_conf']['colors_active_lines'];
                    
                } else {
                    $data['error'] = _t('Извините, у пользователя нет фидов');
                }

            } catch(\Exception $e) {
                $data['error'] = _t('Извините, статистика временно не работает');
            }

            $data = array_merge($data, [
                'lang' => $request->getAttribute('layoutInfo')->getLang(),
                'layoutInfo' => $request->getAttribute('layoutInfo'),
            ]);     

            return new HtmlResponse($this->template->render('app::user/cabinet-feed', $data));
        }
        elseif($request->getAttribute('action') == self::ACTION_CATS)
        {
            try {

                /** @var UserService $auth */
                $auth = $this->container->get(UserService::class);
                $userId = $auth->getIdentity()->getId();
                
                /** @var \App\Model\Feeds\Shops $shopsModel */
                $shopsModel = $this->container->get(\App\Model\Feeds\Shops::class);
                $shop = $shopsModel->findOne(['users_id' => $userId]); // Пока считаем, что у фида один магазин
                
                if($shop) {
                    
                    $shop_id = $shop->getId();

                    // Определяем список фидов магазина:
                    /** @var \App\Model\Feeds\ShopFeeds $shopFeedsModel */
                    $shopFeedsModel = $this->container->get(\App\Model\Feeds\ShopFeeds::class);
                    $shopFeeds = $shopFeedsModel->findAll(['shop_id' => $shop_id]) -> toArray();
                    
                    if (count($shopFeeds) > 0) {
                    
                        /** @var \App\Model\Feeds\Feeds $feedsModel */
                        $feedsModel = $this->container->get(\App\Model\Feeds\Feeds::class);
                        /** @var \App\Model\Feeds\Categories $categoriesModel */
                        $categoriesModel = $this->container->get(\App\Model\Feeds\Categories::class);
                        /** @var \App\Model\Feeds\CategoryFees $categoryFeesModel */
                        $categoryFeesModel = $this->container->get(\App\Model\Feeds\CategoryFees::class);
                        
                        // Формируем древовидную структуру категорий:
                        function get_sub_cats($id, $cats, $parent_cat_percent, $fees) {
                            $sub_cats=[];
                            foreach ($cats as $cat) {
                                if ($cat['parentid'] == $id) {

                                    $cat_percent = $cat['orderpercent'];
                                    $is_own = 1;
                                    if ($cat_percent < 0) {

                                        if ($fees[$cat['id']]) {
                                            $cat_percent = $fees[$cat['id']];
                                        } else {
                                            $cat_percent = $parent_cat_percent;
                                            $is_own = 0;
                                        }

                                    }

                                    $cat['own'] = $is_own;
                                    $cat['percent'] = $cat_percent/10;
                                    $cat['sub_cats'] = get_sub_cats($cat['id'], $cats, $cat_percent, $fees);
                                    $sub_cats[] = $cat;
                                }
                            }
                            return $sub_cats;
                        }

                        // Определяем список категорий у фидов магазина:
                        $feeds_cats = [];
                        foreach ($shopFeeds as $shopFeed) {

                            $feed_id = $shopFeed['feed_id'];
                            $feed = $feedsModel->findOne(['id' => $feed_id]);
                            $feed_title = $feed->getTitle();
                            $feed_percent = $feed->getOrderpercent();
                            
                            // fees категорий фида:
                            $feed_category_fees = $categoryFeesModel->findAll(['FeedID' => $feed_id]) -> toArray();
                            $fees = [];
                            foreach ($feed_category_fees as $feed_category_fee) {
                                $fees[$feed_category_fee['catid']] = $feed_category_fee['orderpercent'];
                            }

                            // Определяем список категорий фида:
                            $cats_list = $categoriesModel->findAll(['FeedID' => $feed_id], 'Title ASC') -> toArray();
                            
                            $feed_cats = [];
                            foreach ($cats_list as $cat) {
                                
                                if ($cat['parentid'] == 0) {
                                    $cat_percent = $cat['orderpercent'];
                                    $is_own = 1;
                                    if ($cat_percent < 0) {
                                        if ($fees[$cat['id']]) {
                                            $cat_percent = $fees[$cat['id']];
                                        } else {
                                            $cat_percent = $feed_percent;
                                            $is_own = 0;
                                        }
                                    }

                                    $cat['own'] = $is_own;
                                    $cat['percent'] = $cat_percent/10;
                                    $cat['sub_cats'] = get_sub_cats($cat['id'], $cats_list, $cat_percent, $fees);
                                    $feed_cats[] = $cat;
                                }
                            }
                            
                            $feeds_cats[] = array(
                                'id' => $feed_id,
                                'title' => $feed_title,
                                'percent' => $feed_percent/10,
                                'cats' => $feed_cats,
                            );

                        }

                        // Список отчетов:
                        $reports_list = [];
                        $reports_conf = $this->container->get('config')['feed_conf']['reports'];
                        foreach($reports_conf as $report_name => $report_value) {
                            $reports_list[$report_name] = $report_value['title'];
                        }
                        
                        $shop_edit_enable = $shop->getEditEnable();
                        //$shop_edit_enable = true;
                        
                        $data['lang'] = $request->getAttribute('layoutInfo')->getLang();
                        $data['feeds_cats'] = $feeds_cats;
                        $data['reports_list'] = $reports_list;
                        $data['edit_enable'] = $shop_edit_enable;
                        
                        
                    } else {
                        $data['error'] = _t('Извините, у магазинов пользователя нет фидов ');
                    }

                } else {
                    $data['error'] = _t('Извините, у пользователя нет магазина');
                }

            } catch(\Exception $e) {
                $data['error'] = _t('Извините, категории временно не доступны');
            }
            
            $data = array_merge($data, [
                'lang' => $request->getAttribute('layoutInfo')->getLang(),
                'layoutInfo' => $request->getAttribute('layoutInfo'),
            ]);     

            return new HtmlResponse($this->template->render('app::user/cabinet-cats', $data));
        }    
        
    }
    
    private function getStatData(ServerRequestInterface $request) 
    {
        /** @var UserService $auth */
        $auth = $this->container->get(UserService::class);
        $userId = $auth->getIdentity()->getId();
        
        /** @var \App\Model\Statistics $stats */
        $stats = $this->container->get(Statistics::class);
        
        // Выводим стр. по фидам, если за пользователем закреплен фид:
        /** @var \App\Model\Feeds $feedsModel */
        $feedsModel = $this->container->get(Feeds::class);
        $feeds = $feedsModel->findAll(['clientid' => $userId])->toArray();
        
        // Фиды пользователя:
        $feed_id_list = [];
        foreach($feeds as $feed_item) {
            $feed_id = $feed_item['id'];
            if (!in_array($feed_id, $feed_id_list)) {
                $feed_id_list[] = $feed_id;
            }
        }         
        
        $report_type = $request->getAttribute('report');
        $data_request = $request->getParsedBody();
        
        // Подтверждение (или его отмена) заказов:
        if ($data_request['toggle_confirmed']) {
                        
            /** @var \App\Model\Feeds $ordersStatusModel */
            $ordersStatusModel = $this->container->get(OrdersStatus::class);
            
            /** @var DelegatingHydrator $hydrator */
            $hydrator = $this->container->get(DelegatingHydrator::class);
            
            $feed_id = $data_request['feedId'];
            if (in_array($feed_id, $feed_id_list)) {
                
                $order_id = $data_request['orderId'];
                $ordersStatus = $ordersStatusModel->findOne(['feed_id' => $feed_id, 'order_id' => $order_id]);

                if ($ordersStatus) {
                    
                    $order_is_approved = $ordersStatus->getApproved();
                    if (!$order_is_approved) {
                        if ($data_request['confirmed']) {
                            // Удаляем запись т.к. подтвержденныс считается по-умолчанию:
                            $res = $ordersStatusModel->deleteRetargOrderStatus($ordersStatus);
                            if(!$res) {
                                throw new \Exception('DB error');
                            }
                        }
                        /*
                        else {
                            // Этот кусок по логике не используется, т.к. не можем менять confirmed у заказов approved
                            $data = array(
                                'feed_id' => $feed_id,
                                'order_id' => $order_id,
                                'confirmed' => $data_request['confirmed'],
                                'approved' => 0
                            );
                            $orderStatus = $hydrator->hydrate($data, new OrderStatus());
                            $res = $ordersStatusModel->saveRetargOrderStatus($orderStatus, 'insert');
                            if(!$res) {
                                throw new \Exception('DB error');
                            }
                            
                        }*/
                    }
                } else {
                    
                    $data = array(
                        'feed_id' => $feed_id,
                        'order_id' => $order_id,
                        'confirmed' => $data_request['confirmed'],
                        'approved' => 0,
                        'comment' => ($data_request['comment']) ? $data_request['comment'] : null,
                    );
                    $orderStatus = $hydrator->hydrate($data, new OrderStatus());
                    $res = $ordersStatusModel->saveRetargOrderStatus($orderStatus, 'insert');
                    if(!$res) {
                        throw new \Exception('DB error');
                    }
                }
                return new JsonResponse(array(
                    'result' => true,
                    'data' => $res,
                    'confirmed' => (bool)$data_request['confirmed']
                ));
            }
            return new JsonResponse(array(
                'result' => false,
                'msg' => 'Фид не принадлежит пользователю',
            ));
        }
        
        // Утверждение заказов:
        if ($data_request['approved']) {
        
            /** @var \App\Model\Feeds $ordersStatusModel */
            $ordersStatusModel = $this->container->get(OrdersStatus::class);
            
            /** @var DelegatingHydrator $hydrator */
            $hydrator = $this->container->get(DelegatingHydrator::class);
            
            $approved_orders = [];
            foreach($data_request['orders'] as $order_item) {
                $feed_id = $order_item['feedId'];
                if (in_array($feed_id, $feed_id_list)) {
                    
                    $order_id = $order_item['orderId'];
                    $ordersStatus = $ordersStatusModel->findOne(['feed_id' => $feed_id, 'order_id' => $order_id]);
                    
                    if ($ordersStatus) {
                        $order_is_approved = $ordersStatus->getApproved();
                        if (!$order_is_approved) {
                            $ordersStatus->setApproved($order_item['approved']);
                            $res = $ordersStatusModel->saveRetargOrderStatus($ordersStatus, 'update');
                            if(!$res) {
                                throw new \Exception('DB error');
                            }
                            $approved_orders[] = $res;
                        }
                    } else {
                        $data = array(
                            'feed_id' => $feed_id,
                            'order_id' => $order_id,
                            'confirmed' => $order_item['confirmed'],
                            'approved' => $order_item['approved']
                        );
                        $orderStatus = $hydrator->hydrate($data, new OrderStatus());
                        $res = $ordersStatusModel->saveRetargOrderStatus($orderStatus, 'insert');
                        if(!$res) {
                            throw new \Exception('DB error');
                        }
                        $approved_orders[] = $res;
                    }
                }
            }

            return new JsonResponse(array(
                'result' => true,
                'data' => $approved_orders,
            ));
        }
        
        
        
        $dates = $data_request['period'];
        
        $report_conf = $this->container->get('config')['feed_conf']['reports'][$report_type];
        
        switch ($report_type) {
            case 'common':
                $periodStats = $stats->getFeedStatData($report_type, $feed_id_list, $dates, $report_conf);
                break;
            case 'transactions':
                $periodStats = $stats->getFeedStatData($report_type, $feed_id_list, $dates, $report_conf);
                break;
            default:
                $periodStats = null;
                break;
        }
        
        if (!$periodStats) {
            return new JsonResponse(null);
        }
        
        // Добавляем спец. категории для сводного отчета по магазину:
        if ($report_type == 'common') {
            $periodStats = $this->addStatsSpecialCats($periodStats);
        }
        
        // Добавляем данные о статусах заказов:
        if ($report_type == 'transactions') {
            /** @var \App\Model\Feeds $ordersStatusModel */
            $ordersStatusModel = $this->container->get(OrdersStatus::class);
            $ordersStatus = $ordersStatusModel->findAll(['feed_id' => $feed_id_list])->toArray();
            $statuses = [];
            foreach($ordersStatus as $order_item) {
                $statuses[$order_item['feed_id']][$order_item['order_id']] = array(
                    'confirmed' => $order_item['confirmed'] ? 1 : 0,
                    'approved' => $order_item['approved'] ? 1 : 0
                );
            }
            $periodStats['ordersStatus'] = $statuses;
        }
        
        $data = $periodStats;
        
        return new JsonResponse($data);
    }
    
    private function editCatsData(ServerRequestInterface $request)
    {
        $data = $request->getParsedBody();
        $cats = json_decode($data['cats'], true);
        
        $cats_id = array_keys($cats);
        
        /** @var \App\Model\Feeds\CategoryFees $categoryFeesModel */
        $categoryFeesModel = $this->container->get(\App\Model\Feeds\CategoryFees::class);
        
        /** @var DelegatingHydrator $hydrator */
        $hydrator = $this->container->get(DelegatingHydrator::class);
        
        
        foreach ($cats_id as $cat) {
            $category_fee = $categoryFeesModel->findOne(['CatID' => $cat]);
            
            if ($category_fee) {
                if ($cats[$cat]['p']) {
                    $category_fee->setOrderpercent($cats[$cat]['p']);
                    $result = $categoryFeesModel->saveRetargCatFee($category_fee, 'update');
                } else {
                    $result = $categoryFeesModel->deleteRetargCatFee($category_fee);
                }
                if(!$result) {
                    throw new \Exception('DB error');
                }
            } else {
                
                $cat_item = $cats[$cat];
                
                $data = array(
                    'feedid' => $cat_item['fi'],
                    'catid' => $cat_item['id'],
                    'foreigncatid' => $cat_item['fc'],
                    'orderpercent' => $cat_item['p']
                );
                $categoryFee = $hydrator->hydrate($data, new CategoryFee());
                $result = $categoryFeesModel->saveRetargCatFee($categoryFee, 'insert');
                if(!$result) {
                    throw new \Exception('DB error');
                }
            }
        }
        
        $response = new JsonResponse([
            'result' => true,
            'redirect' => $this->router->generateUri('user.cabinet.cats', [
                'lang' => $request->getAttribute('layoutInfo')->getLang(),
            ])
        ]);
        return $response;
    }
    
    // Добавляем категории для сводного отчета по магазину:
    private function addStatsSpecialCats($periodStats)
    {
        if ($periodStats) {
            $periodStats['ctr'] = [];
            foreach($periodStats['period'] as $ind => $period) {
                $views_value = $periodStats['Views'][$ind];
                $clicks_value = $periodStats['Clicks'][$ind];
                $periodStats['ctr'][] = ($views_value != 0) ? round(($clicks_value/$views_value)*100, 2) : 0;
            }
        }
        return $periodStats;
    }

    
}