<?php
/**
 * 2007-2022 PrestaShop
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@prestashop.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
 * versions in the future. If you wish to customize PrestaShop for your
 * needs please refer to http://www.prestashop.com for more information.
 *
 * @author    PrestaShop SA <contact@prestashop.com>
 * @copyright 2007-2022 PrestaShop SA
 * @license   http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
 *  International Registered Trademark & Property of PrestaShop SA
 */

require_once dirname(__FILE__) . '/AdminEtsHDBaseController.php';

class AdminEtsHDDashboardController extends AdminEtsHDBaseController
{
    public $filterType;
    public $fromTime;
    public $toTime;
    public $filter_types = array();
    public $jsons = array();

    public function __construct()
    {
        $this->bootstrap = true;
        parent::__construct();

        $this->filter_types = array(
            'today' => array(
                'id' => 'today',
                'label' => $this->l('Today'),
            ),
            'tomorrow' => array(
                'id' => 'tomorrow',
                'label' => $this->l('Day -1'),
            ),
            'month' => array(
                'id' => 'month',
                'label' => $this->l('Month'),
            ),
            'last_month' => array(
                'id' => 'last_month',
                'label' => $this->l('Month -1'),
            ),
            'time_range' => array(
                'id' => 'time_range',
                'range' => array(
                    array(
                        'id' => 'from',
                        'label' => $this->l('From'),
                    ),
                    array(
                        'id' => 'to',
                        'label' => $this->l('To'),
                    )
                )
            ),
        );
    }

    public function setMedia($isNewTheme = false)
    {
        parent::setMedia($isNewTheme);

        $this->addJS(array(
            //$this->module->getPathUri() . 'views/js/helpdesk.chart.js',
            $this->module->getPathUri() . 'views/js/chart.admin.js',
            $this->module->getPathUri() . 'views/js/helpdesk.dashboard.js',
        ));

        $this->addCSS($this->module->getPathUri() . 'views/css/helpdesk.ticket.css');
    }

    public function initLineChart()
    {
        $this->filterType = trim(Tools::getValue('filter_type'));
        if (trim($this->filterType) == '' ||
            !Validate::isCleanHtml(trim($this->filterType)) ||
            trim($this->filterType) !== 'all'
            && !isset($this->filter_types[trim($this->filterType)])
        ) {
            $this->filterType = self::$default_type;
        }
        $this->fromTime = $this->toTime = null;
        if ($this->filterType == 'time_range') {
            $this->fromTime = trim(Tools::getValue('from'));
            $this->toTime = trim(Tools::getValue('to'));
            if ($this->fromTime == '') {
                $this->errors[] = $this->l('"From" time is required.');
            } elseif (!Validate::isDate($this->fromTime)) {
                $this->errors[] = $this->l('"From" time is invalid.');
            }
            if ($this->toTime == '') {
                $this->errors[] = $this->l('"To" time is required');
            } elseif (!Validate::isDate($this->toTime)) {
                $this->errors[] = $this->l('"To" time is invalid.');
            }
            if (strtotime($this->fromTime) >= strtotime($this->toTime)) {
                $this->errors[] = $this->l('"To" time more than "From" time.');
            }
        }
        if (count($this->errors) && $this->ajax) {
            die(json_encode(array(
                'errors' => Tools::nl2br(implode(PHP_EOL, $this->errors)),
            )));
        }
    }

    public function initContent()
    {
        $this->display = 'view';
        parent::initContent();
    }

    /**
     * @param $type
     * @param DbQuery $query
     * @param $query_shop
     * @param $field
     * @param null $selectTime
     * @param int $minX
     * @param int $maxX
     * @param null $time_series
     * @param null $labelX
     * @return mixed
     */

    public function getQueriesTime($type, &$query, &$query2, $field = null, $from = null, $to = null, $selectTime = null, $minX = 0, $maxX = 0, &$time_series = null, &$labelX = null)
    {
        if ($time_series !== null && !is_array($time_series)) {
            $time_series = array();
        }
        $labelX = $this->l('Year(s)');
        $unionQuery = ' SELECT ';
        switch ($type) {
            case 'all':
                $time = $selectTime !== null ? $selectTime : time();
                $min = $minX ?: 1970;
                $max = $maxX ?: (int)date('Y', $time);
                for ($year = $min; $year <= $max; $year++) {
                    $unionQuery .= $year . ' as `year` ' . ($year < $max ? ' UNION SELECT ' : '');
                    $time_series[] = $year;
                }
                $query
                    ->select('ts.year')
                    ->join('RIGHT JOIN (' . $unionQuery . ') ts ON (ts.year = YEAR(' . $field . ') AND @JOIN@)')
                    ->groupBy('ts.year');
                break;
            case 'year':
                $time = $selectTime !== null ? $selectTime : time();
                $labelX = $this->l('Month(s)');
                $months = Tools::dateMonths();
                foreach ($months as $month => $labelAxesX) {
                    if ($minX && $maxX && ($month >= $minX && $month <= $maxX) || !$minX && !$maxX) {
                        $unionQuery .= $month . ' as `month` ' . ($month < ($maxX ?: 12) ? ' UNION SELECT ' : '');
                        $time_series[] = $labelAxesX;
                    }
                }
                $query
                    ->select('ts.month')
                    ->join('RIGHT JOIN (' . $unionQuery . ') ts ON (ts.month = MONTH(' . $field . ') AND YEAR(' . $field . ') = ' . (int)date('Y', $time) . ' AND @JOIN@)')
                    ->groupBy('ts.month');
                break;
            case 'month':
            case 'last_month':
                $time = $selectTime !== null ? $selectTime : ($type !== 'month' ? strtotime('-1 month') : time());
                if ($time_series !== null) {
                    $labelX = $this->l('Day(s)');
                    $daysOfMonth = (int)date('t', mktime(0, 0, 0, (int)date('m', $time), 1, (int)date('Y', $time)));
                    for ($day = 1; $day <= $daysOfMonth; $day++) {
                        if ($minX && $maxX && ($day >= $minX && $day <= $maxX) || !$minX && !$maxX) {
                            $unionQuery .= $day . ' as `day` ' . ($day < ($maxX ?: $daysOfMonth) ? ' UNION SELECT ' : '');
                            $time_series[] = $day;
                        }
                    }
                    $query
                        ->select('ts.day')
                        ->join('RIGHT JOIN (' . $unionQuery . ') ts ON (ts.day = DAY(' . $field . ') AND MONTH(' . $field . ') = ' . (int)date('m', $time) . ' AND YEAR(' . $field . ') = ' . (int)date('Y', $time) . ' AND @JOIN@)')
                        ->groupBy('ts.day');
                }
                if ($query2 !== null) {
                    $query2
                        ->where('MONTH(' . $field . ') = ' . (int)date('m', $time) . ' AND YEAR(' . $field . ') = ' . (int)date('Y', $time));
                }
                break;
            case 'today':
            case 'tomorrow':
                $time = $selectTime !== null ? $selectTime : ($type !== 'day' ? strtotime('-1 day') : time());
                if ($time_series !== null) {
                    $labelX = $this->l('Hour(s)');
                    for ($hour = 0; $hour <= 23; $hour++) {
                        if ($minX && $maxX && ($hour >= $minX && $hour <= $maxX) || !$minX && !$maxX) {
                            $unionQuery .= $hour . ' as `hour` ' . ($hour < ($maxX ?: 23) ? ' UNION SELECT ' : '');
                            $time_series[] = date('g:i A', strtotime($hour . ':00'));
                        }
                    }
                    $query
                        ->select('ts.hour')
                        ->join('RIGHT JOIN (' . $unionQuery . ') ts ON (ts.hour = HOUR(' . $field . ') AND DAY(' . $field . ') = ' . (int)date('d', $time) . ' AND MONTH(' . $field . ') = ' . (int)date('m', $time) . ' AND YEAR(' . $field . ') = ' . (int)date('Y', $time) . ' AND @JOIN@)')
                        ->groupBy('ts.hour');
                }
                if ($query2 !== null) {
                    $query2
                        ->where('DAY(' . $field . ') = ' . (int)date('d', $time) . ' AND MONTH(' . $field . ') = ' . (int)date('m', $time) . ' AND YEAR(' . $field . ') = ' . (int)date('Y', $time));
                }
                break;
            case 'time_range':
                $time_from = strtotime($from);
                $time_to = strtotime($to);
                if ($query2 !== null) {
                    $query2
                        ->where('DATE(' . $field . ') BETWEEN \'' . pSQL(date('Y-m-d', $time_from)) . '\' AND \'' . pSQL(date('Y-m-d', $time_to)) . '\'');
                }
                if ($time_series !== null) {
                    $query3 = clone $query2;
                    if ((int)date('Y', $time_from) != ($year = (int)date('Y', $time_to))) {
                        return $this->getQueriesTime('all', $query, $query3, $field, null, null, null, (int)date('Y', $time_from), $year, $time_series, $labelX);
                    } elseif ((int)date('m', $time_from) != ($month = (int)date('m', $time_to))) {
                        return $this->getQueriesTime('year', $query, $query3, $field, null, null, $time_to, (int)date('m', $time_from), $month, $time_series, $labelX);
                    } elseif ((int)date('d', $time_from) != ($day = (int)date('d', strtotime($to)))) {
                        return $this->getQueriesTime('month', $query, $query3, $field, null, null, $time_to, (int)date('d', $time_from), $day, $time_series, $labelX);
                    } else {
                        return $this->getQueriesTime('day', $query, $query3, $field, null, null, $time_to, (int)date('H', $time_from), (int)date('H', $time_to), $time_series, $labelX);
                    }
                }
                break;
        }
    }

    public function getTicketsNumber($query)
    {
        $tpl_vars = array(
            'received' => array(
                'label' => $this->l('Received'),
                'value' => HDTicket::queriesTickets(1, $query),
                'type' => 'int',
            ),
            'pending' => array(
                'label' => $this->l('Pending'),
                'value' => HDTicket::queriesTickets(1, $query, array('open')),
                'type' => 'int',
            ),
            'closed' => array(
                'label' => $this->l('Closed'),
                'value' => HDTicket::queriesTickets(1, $query, array('closed')),
                'type' => 'int',
            )
        );

        $mp = HDTicket::getMostProductSupport($query);
        $has_product_support = isset($mp['id_product']) && (int)$mp['id_product'] > 0;
        if ($has_product_support) {
            $p = new Product((int)$mp['id_product'], false, $this->context->language->id);
            if (isset($mp['product_logo']) && trim($mp['product_logo']) !== '' && @file_exists(_PS_ROOT_DIR_ .'/'. $mp['product_logo'])) {
                $logo = $this->context->shop->getBaseURI() . $mp['product_logo'];
            } else {
                $image = Product::getCover($p->id, $this->context);
                $logo = $this->context->link->getImageLink($p->link_rewrite, isset($image['id_image']) ? $image['id_image'] : 0, HDTools::getImageType('small'));
            }
        }

        $tpl_vars['most_product_support'] = array(
            'label' => $this->l('Most support product'),
            'value' => $has_product_support ? array(
                'logo' => $logo,
                'name' => $p->name,
                'link' => $this->context->link->getProductLink($p),
            ) : array(),
            'type' => 'image',
        );

        $staff = HDTicket::getMostStaffSupport($query);
        $tpl_vars['most_staff_support'] = array(
            'label' => $this->l('Most staff support'),
            'value' => $staff ? trim($staff['staff']) : '',
            'type' => 'text',
        );

        $avg_response_time = HDTicket::getAverageResponseTime($query);
        $tpl_vars['avg_response_time'] = array(
            'label' => $this->l('Average response time'),
            'value' => $this->displayResponseTime($avg_response_time),
            'type' => 'time',
        );

        $this->context->smarty->assign(array(
            'tickets_number' => $tpl_vars
        ));

        if ($this->ajax) {
            $this->jsons['tickets_number'] = $this->createTemplate('ticket-number.tpl')->fetch();
        }
    }

    public function displayResponseTime($responseTime)
    {
        $responseTime = (int)$responseTime;
        $displayEsTime = '';
        $hours = (int)($responseTime / 3600);
        if ($hours >= 1) {
            $displayEsTime = $hours . ' ' . ($hours > 1 ? $this->l('hours') : $this->l('hour'));
            $minutes = (int)(($responseTime - $hours * 3600) / 60);
            if ($minutes > 0) {
                $displayEsTime .= ' ' . $minutes . ' ' . ($minutes > 1 ? $this->l('minutes') : $this->l('minute'));
            }
        } else {
            $minutes = (int)($responseTime / 60);
            if ($minutes > 0) {
                $displayEsTime .= $minutes . ' ' . ($minutes > 1 ? $this->l('minutes') : $this->l('minute'));
            } else {
                $seconds = (int)($responseTime - $minutes * 60);
                $displayEsTime .= ($seconds > 0 ? $seconds : 0) . ' ' . ($seconds > 1 ? $this->l('seconds') : $this->l('second'));
            }
        }
        return $displayEsTime;
    }

    public function getLineCharts($query, $axesX, $dataAxesX)
    {
        $received = HDTicket::queriesTickets(0, $query, array());
        $dataset_received = array();
        foreach ($received as $item) {
            $dataset_received[] = (int)$item['ticket'];
        }
        $pending = HDTicket::queriesTickets(0, $query, array('open'));
        $dataset_pending = array();
        foreach ($pending as $item) {
            $dataset_pending[] = (int)$item['ticket'];
        }
        $closed = HDTicket::queriesTickets(0, $query, array('closed'));
        $dataset_closed = array();
        foreach ($closed as $item) {
            $dataset_closed[] = (int)$item['ticket'];
        }
        $line_charts = array(
            'title' => $this->l('Tickets chart'),
            'axesX' => $axesX,
            'axesY' => $this->l('Ticket(s)'),
            'datasets' => array(
                array(
                    'label' => $this->l('Received'),
                    'data' => $dataset_received,
                    'backgroundColor' => '#ffc0cb',
                    'borderColor' => '#ffc0cb',
                    'borderWidth' => 1,
                    'fill' => false,
                    'tension' => 0,
                ),
                array(
                    'label' => $this->l('Pending'),
                    'data' => $dataset_pending,
                    'backgroundColor' => '#fdc107',
                    'borderColor' => '#fdc107',
                    'borderWidth' => 1,
                    'fill' => false,
                    'tension' => 0,
                ),
                array(
                    'label' => $this->l('Closed'),
                    'data' => $dataset_closed,
                    'backgroundColor' => '#8bc348',
                    'borderColor' => '#8bc348',
                    'borderWidth' => 1,
                    'fill' => false,
                    'tension' => 0,
                )
            ),
            'dataAxesX' => $dataAxesX,
        );
        if ($this->ajax) {
            $this->jsons['line_charts'] = $line_charts;
        } else {
            $this->context->smarty->assign(array(
                'line_charts' => $line_charts
            ));
        }
    }

    public function getTopSupportModules($query)
    {
        $top_modules = HDTicket::getTopSupportModules($query, $this->context);
        if ($top_modules) {
            foreach ($top_modules as &$tm) {
                $product = new Product((int)$tm['id_product'], false, $this->context->language->id);
                $tm['product_link'] = $this->context->link->getProductLink($product, null, null, null, $this->context->language->id);
                if (isset($tm['product_logo']) && trim($tm['product_logo']) !== '' && @file_exists(_PS_ROOT_DIR_ .'/'. $tm['product_logo'])) {
                    $logo = $this->context->shop->getBaseURI() . $tm['product_logo'];
                } else {
                    $image = Product::getCover($product->id, $this->context);
                    $logo = $this->context->link->getImageLink($product->link_rewrite, isset($image['id_image']) ? $image['id_image'] : 0, HDTools::getImageType('small'));
                }
                $tm['product_logo'] = $logo;
                $tm['staff'] = isset($tm['recent_ticket']) && $tm['recent_ticket'] !== '' ? HDTicket::getTicketsOf(explode(',', $tm['recent_ticket'])) : null;
                $tm['recent_ticket'] = $tm['recent_ticket'] !== '' ? array_map('intval',explode(',',$tm['recent_ticket'])) :array();
                //$tm['view']  = $this->context->link->getAdminLink('AdminProducts', true, $this->module->ps17 ? ['route' => 'admin_customers_view', 'customerId' => (int)$tr['id_customer']] : [], ['viewcustomer' => '', 'id_customer' => (int)$tr['id_customer']]);
            }
        }
        $this->context->smarty->assign(array(
            'top_modules' => $top_modules
        ));
        if ($this->ajax) {
            $this->jsons['top_modules'] = $this->createTemplate('top-modules.tpl')->fetch();
        }
    }

    public function getTopSupportStaffs($query)
    {
        $top_staffs = HDTicket::getTopSupportStaffs($query);
        if ($top_staffs) {
            foreach ($top_staffs as &$row) {
                if (trim($row['avatar']) == '' || !file_exists(HDDefines::$avatar_upload . trim($row['avatar']))) {
                    $avatar = (int)$row['id_employee'] > 0 ? Configuration::get('ETS_HD_EMPLOYEE_AVATAR_DEFAULT') : Configuration::get('ETS_HD_CUSTOMER_AVATAR_DEFAULT');
                    $row['avatar'] = $avatar && file_exists(HDDefines::$avatar_upload . $avatar) ? $avatar : '';
                }
                if (trim($row['avatar']) !== '') {
                    $row['avatar'] = HDDefines::$avatar_base_uri . $row['avatar'];
                } else {
                    $avatar = (int)$row['id_employee'] > 0 ? HDDefines::$employee_avatar_default : HDDefines::$customer_avatar_default;
                    $row['avatar'] = $avatar && file_exists($this->module->getLocalPath() . 'views/img/' . $avatar) ? $this->module->getMediaLink($this->module->getPathUri() . 'views/img/' . $avatar) : '';
                }
            }
        }
        $this->context->smarty->assign(array(
            'top_staffs' => $top_staffs
        ));
        if ($this->ajax) {
            $this->jsons['top_staffs'] = $this->createTemplate('top-staffs.tpl')->fetch();
        }
    }

    static $default_type = 'month';

    public function renderView()
    {
        $this->initLineChart();

        $dq = new DbQuery();
        $dq2 = clone $dq;
        $dataAxesX = array();
        $axesX = null;
        $this->getQueriesTime($this->filterType, $dq, $dq2, 'a.date_add', $this->fromTime, $this->toTime, null, null, null, $dataAxesX, $axesX);
        $this->getTicketsNumber($dq2);
        $this->getLineCharts($dq, $axesX, $dataAxesX);
        $this->getTopSupportModules($dq2);
        $this->getTopSupportStaffs($dq2);

        if (!$this->ajax) {
            $this->context->smarty->assign(array(
                'filter_types' => $this->filter_types,
                'default_type' => self::$default_type,
            ));

            return $this->createTemplate('dashboard.tpl')->fetch();
        }
    }

    public function ajaxProcessUpdateStats()
    {
        $this->renderView();

        die(json_encode($this->jsons));
    }
}