<?php

namespace App\Model;

use DateTime;

class Statistics 
{   
    private $hashSolt = '';
    
    public function __construct(/*Sites $sites, Zones $zones, $countries*/) 
    {
        $this->hashSolt = 'FsRpCKc021PzwqOR8o1mXLe8AIS6YmnfkDvECBY6MzGWHhceS4EvdOnW7dYHt7AA';
    }

    
    // Данные по отчетам фидов
    public function getFeedStatData($report_type, $feed_id_list, $dates, $report_conf)
    {
        
        $timeDiff = (strtotime($dates[1])-strtotime($dates[0]))/(24*60*60);
        // Определяем разрешение выборки (группировку) по времени:
        if ($timeDiff == 0) // Одни сутки
        {
            $dates_group = "Min";
        }
        else                // Несколько суток
        {
            $dates_group = "Day";
        }
        
        $dates = array(
            'group' => $dates_group,
            'start'  => $dates[0], 
            'end'  => $dates[1],
        );
        
        // Параметры запроса по типу отчета:
        $type = $report_conf['type'];
        $fields = $report_conf['fields'];
                
        // Данные для запроса:
        if ($report_type == 'common') {
            $dataRequest = array(
                'method' => "reports",
                'data' => array(
                    'type' => $type,
                    'filters'  => array(
                        'FeedID' => array('values' => $feed_id_list),
                    ),
                    'fields'  => $fields,
                    'dates' => $dates,
                )      
            );
        }
        
        if ($report_type == 'transactions') {
            $dataRequest = array(
                'method' => $type,
                'data' => array(
                    'feed_id' => $feed_id_list,
                    'start_date' => $dates['start'],
                    'end_date' => $dates['end'],
                )      
            );
        }
        
        //return $dataRequest;
        //$stats = $this->apiRequest($dataRequest);
        //return $stats;
        try {
            $stats = $this->apiRequest($dataRequest);
        } catch (\Exception $e) {
            $stats['status'] = 'Error';
        }
        //return $stats;

        
        // В запросе ошибка или отсутствуют данные для статистики:
        if ($stats['status'] == 'Error') {
            return $stats;
        }
        if ($stats['data'] == []) {
            return null;
        }
        
        $dataStats = array();
        $dataStats['report'] = $report_type;
        
        // Данные для отчета 'common':
        if ($report_type == 'common') {
        
            $period = array();

            // Формируем данные для временного промежутка
            function AddDataStats(&$data_stats, $data, $date_type)
            {
                $min_koef = ($date_type == 'interval') ? 1 : 5;
                foreach ($data as $cat=>$value) {
                    $data_stats[$cat][] = $value/$min_koef;
                }
                //$data_stats['AdMoney'][] = 224 * $data['Orders']; // временно
            }
            
            function AddDataStatsFixedAdMoney(&$data_stats, $data, $date_type)
            {
                foreach ($data as $cat=>$value) {
                    if ($cat == 'AdMoney') {
                        $data_stats['AdMoney'][] = 224 * $data['Orders'];
                    } else {
                        $data_stats[$cat][] = $value;
                    }
                }
            }

            // Формируем пустые данные для временного промежутка
            function AddDataStatsNull(&$data_stats, $cats)
            {
                foreach ($cats as $cat) {
                    $data_stats[$cat][] = 0;
                }
                //$data_stats['AdMoney'][] = 0; // временно
            }

            // Логика формирования данных по временному интервалу:
            /*
            if (false) {
                if ($timeDiff == 0) // Одни сутки
                {
                    $dataStats['type'] = 'day';

                    // Формируем пустые данные (для отсутствующих значений во временной точке):
                    foreach ($stats['data']['Day'] as $day=>$value_day) {
                        foreach ($value_day['Min'] as $min=>$data) {
                            $data_null = $data;
                            break;
                        }
                        break;
                    }
                    foreach ($data_null as $key=>$value) {
                        $data_null[$key] = 0;
                    }
                    // Формируем 5-минутные интервалы:
                    for ($i=0; $i<288; $i++) {
                        $min = $i * 60 * 5;
                        $period[] = gmdate("H:i", $min);
                    }

                    foreach ($stats['data']['Day'] as $day) {
                        // Формируем временные интервалы, для которых есть значения:
                        $dates_min = [];
                        foreach (array_keys($day['Min']) as $min) {
                            $dates_min[date("H:i", strtotime($min))] = $min;
                        }

                        foreach ($period as $min_value) {
                            $value_min = ($dates_min[$min_value]) ? $day['Min'][$dates_min[$min_value]] : $data_null;
                            AddDataStats($dataStats, $value_min, $metric, $dataStats['type']);
                        }
                    }

                }
                elseif (!$by_days) // Набор дат
                {
                    $dataStats['type'] = 'compare';

                    // Формируем пустые данные (для отсутствующих значений во временной точке):
                    foreach ($stats['data']['Day'] as $day=>$value_day) {
                        foreach ($value_day['Min'] as $min=>$data) {
                            $data_null = $data;
                            break;
                        }
                        break;
                    }
                    foreach ($data_null as $key=>$value) {
                        $data_null[$key] = 0;
                    }
                    // Формируем 5-минутные интервалы:
                    for ($i=0; $i<288; $i++) {
                        $min = $i * 60 * 5;
                        $period[] = gmdate("H:i", $min);
                    }

                    foreach ($stats['data']['Day'] as $day=>$value_day) {
                        $dataStats[date("Y-m-d", strtotime($day))] = [];
                        // Формируем временные интервалы, для которых есть значения:
                        $dates_min = [];
                        foreach (array_keys($value_day['Min']) as $min) {
                            $dates_min[date("H:i", strtotime($min))] = $min;
                        }

                        foreach ($period as $min_value) {
                            $data = ($dates_min[$min_value]) ? $value_day['Min'][$dates_min[$min_value]] : $data_null;
                            AddDataStats($dataStats[date("Y-m-d", strtotime($day))], $data, $metric, $dataStats['type']);
                        }
                    }

                }
                else // Несколько суток
                {
                    $dataStats['type'] = 'interval';
                    foreach ($stats['data']['Day'] as $day=>$value_day) {
                        $period[] = $day;
                        AddDataStats($dataStats, $value_day, $metric, $dataStats['type']);
                    }
                }
            }
            */
            
            $dataStats['type'] = 'interval';

            // Спискок всех дат из запроса стастистики:
            $all_period = array();
            $begin = new DateTime($dates['start']);
            $end   = new DateTime($dates['end']);
            for($i = $begin; $i <= $end; $i->modify('+1 day')){
                $all_period[] = $i->format("Y-m-d");
            }

            // Список дат, полученных в статистике: 
            $stat_days = array_keys($stats['data']['Day']);
            // Список категорий в данных статистики: 
            $stat_cats = array_keys($stats['data']['Day'][$stat_days[0]]);

            foreach ($all_period as $day_item) {
                $item = new DateTime($day_item);
                $stat_from = new DateTime($stat_days[0]);
                $stat_to = new DateTime($stat_days[count($stat_days)-1]);

                //if (($item>= $stat_from) && ($item<= $stat_to)) {
                if (($item>= $stat_from)) {
                    $period[] = $day_item;
                    if ($stats['data']['Day'][$day_item]) {
                        AddDataStats($dataStats, $stats['data']['Day'][$day_item], $dataStats['type']);
                        /*
                        if (strtotime($day_item)< strtotime('2019-04-01')) {
                            AddDataStatsFixedAdMoney($dataStats, $stats['data']['Day'][$day_item], $dataStats['type']);
                        } else {
                            AddDataStats($dataStats, $stats['data']['Day'][$day_item], $dataStats['type']);
                        }
                        */
                    } else {
                        AddDataStatsNull($dataStats, $stat_cats);
                    }
                }
            }

            /*
            foreach ($stats['data']['Day'] as $day=>$value_day) {
                $period[] = $day;
                AddDataStats($dataStats, $value_day, $dataStats['type']);
            }
            */
            
            $dataStats['period'] = $period;
        }
        
        // Данные для отчета 'transactions':
        if ($report_type == 'transactions') {
            foreach ($stats['data'] as $item) {
                $dataStats['period'][] = [$item['ForeignID'], $item['FeedID']];
                $dataStats['ViewID'][] = $item['ViewID'];
                $dataStats['Timestamp'][] = $item['Timestamp'];
                $dataStats['OrderSum'][] = $item['OrderSum'];
                $dataStats['Basket'][] = $item['Basket'];
                $dataStats['AdMoney'][] = $item['AdMoney'];
                /*
                if (strtotime($item['Timestamp'])< strtotime('2019-04-01')) {
                    $dataStats['AdMoney'][] = 224;
                } else {
                    $dataStats['AdMoney'][] = $item['AdMoney'];
                }
                */
            }
        }
        
        $stats = $dataStats;
        return $stats;
    }
    
    // Данные по статистике по клику
    public function getViewIdStatData($feed_id, $view_id)
    {
        
        $dataRequest = array(
            'method' => 'feed_click_history',
            'data' => array(
                'feed_id' => (int) $feed_id,
                'view_id' => $view_id
            )      
        );
        
        //return $dataRequest;
        //$stats = $this->apiRequest($dataRequest);
        //return $stats;
        
        try {
            $stats = $this->apiRequest($dataRequest);
        } catch (\Exception $e) {
            $stats['status'] = 'Error';
        }
        
        // В запросе ошибка или отсутствуют данные для статистики:
        if ($stats['status'] == 'Error') {
            return $stats;
        }
        if ($stats['data'] == []) {
            return null;
        }
        
        $stats = $stats['data'];
        return $stats;
    }
    
    // Данные по статистике по заказу фида
    public function getOrderIdStatData($feed_id, $order_id)
    {
        $dataRequest = array(
            'method' => 'feed_order_history',
            'data' => array(
                'feed_id' => (int) $feed_id,
                'order_id' => $order_id
            )      
        );
        
        //return $dataRequest;
        //$stats = $this->apiRequest($dataRequest);
        //return $stats;
        
        try {
            $stats = $this->apiRequest($dataRequest);
        } catch (\Exception $e) {
            $stats['status'] = 'Error';
        }
        
        // В запросе ошибка или отсутствуют данные для статистики:
        if ($stats['status'] == 'Error') {
            return $stats;
        }
        if ($stats['data'] == []) {
            return null;
        }
        
        $stats = $stats['data'];
        return $stats;
    }
    
    // Добавление спец. полей в статистики по кампаниям (баннерам)
    private function AddSpecialFields(&$stats)
    {
         if ($taget_action == 'load') {
            $stats['views'] = $stats['loads'];
            $stats['reach'] = $stats['reach_load'];
        } else {
            $stats['reach'] = $stats['reach_view'];
        }
        unset($stats['loads']);
        unset($stats['reach_load']);
        unset($stats['reach_view']);

        $views = $stats['views'];
        $money = $stats['money'];
        $clicks = $stats['clicks'];

        $stats['ctr'] = ($views != 0) ? round(($clicks/$views)*100, 2) : 0;
        $stats['cpm'] = ($views != 0) ? round(($money/$views)*1000, 3) : 0;
        $stats['cpc'] = ($clicks != 0) ? round(($money/$clicks), 2) : 0;

        $stats['money'] = round($stats['money'], 2);
    }
    
    // Данные для статистики по баннерам
    public function getBannersStat($banners_id_list, $taget_action, $dates)
    {
        $dataRequest = array(
            'method' => ($dates) ? 'banner_day' : 'banner_total',
            'data' => array(
                'ids' => $banners_id_list,
            )      
        );
        
        if ($dates) {
            $dataRequest['data']['start_date'] = $dates[0];
            $dataRequest['data']['end_date'] = $dates[1];
        }
        
        //return $dataRequest;
        try {
            $stats = $this->apiRequest($dataRequest);
        } catch (\Exception $e) {
            $stats['status'] = 'Error';
        }
        //return $stats;
        
        if ($stats) {
            $this->AddSpecialFields($stats);
            $dataStats = $stats;
        }
        
        return $dataStats;
    }
    
    // Данные для статистики по кампании (баннеры)
    public function getCampaignsStat($type, $id_list, $taget_action, $dates, $by_days = false)
    {
        if ($type == 'campaign') {
            $method = ($dates) ? 'camp_day' : 'camp_total';
        } else {
            $method = ($dates) ? 'cgroup_day' : 'cgroup_total';
        }

        $dataRequest = array(
            'method' => $method,
            'data' => array(
                'ids' => $id_list,
            )      
        );
        
        if ($dates) {
            
            $dataRequest['data']['start_date'] = $dates[0];
            
            if ($dates[1] && $dates[1] < date("Y-m-d")) {
                $date_end = $dates[1];
            } else {
                $date_end = date("Y-m-d");
            }
            $dataRequest['data']['end_date'] = $date_end;
            
            // последние 90 дней, если кампания долго идет
            /*
            $dateStart = new \DateTime($dates[0]);
            $dateEnd = new \DateTime($date_end);
            $interval = $dateEnd->diff($dateStart);
            if ($interval->d > 3) {
                $dataRequest['data']['start_date'] = $dateEnd->modify('-3 day')->format('Y-m-d');
            }
            */
            
            if ($by_days) {
                $dataRequest['data']['by_days'] = true;
            }
        }
        
        //return $dataRequest;
        try {
            $stats = $this->apiRequest($dataRequest);
        } catch (\Exception $e) {
            $stats['status'] = 'Error';
            return $stats;
        }
        //return $stats;
        
        if ($stats) {
            
            if (!$dates || !$by_days)
            {
                $this->AddSpecialFields($stats);
                $dataStats = $stats;
            }
            else
            {
                foreach ($stats as $day => $stat) {
                    $this->AddSpecialFields($stats[$day]);
                }
                
                // Формируем данные для временного промежутка
                function AddDataStats(&$data_stats, $data)
                {
                    foreach ($data as $cat=>$value) {
                        $data_stats[$cat][] = $value;
                    }
                }
                
                // Формируем пустые данные для временного промежутка
                function AddDataStatsNull(&$data_stats, $cats)
                {
                    foreach ($cats as $cat) {
                        $data_stats[$cat][] = 0;
                    }
                }

                // Спискок всех дат из запроса стастистики:
                $all_period = array();
                $begin = new DateTime($dates[0]);
                $end   = new DateTime($dates[1]);
                for($i = $begin; $i <= $end; $i->modify('+1 day')){
                    $all_period[] = $i->format("Y-m-d");
                }

                // Список дат, полученных в статистике: 
                $stat_days = array_keys($stats);
                
                // Список категорий в данных статистики: 
                $stat_cats = array_keys($stats[$stat_days[0]]);

                $dataStats = [];
                
                foreach ($all_period as $day_item) {
                    $item = new DateTime($day_item);
                    $stat_from = new DateTime($stat_days[0]);
                    $stat_to = new DateTime($stat_days[count($stat_days)-1]);

                    if ($dates[1] && $dates[1] < date("Y-m-d")) {
                        $period[] = $day_item;
                        if ($stats[$day_item]) {
                            AddDataStats($dataStats, $stats[$day_item]);
                        } else {
                            AddDataStatsNull($dataStats, $stat_cats);
                        }
                    } else {
                        //Если у кампании конца нет, то по последний день когда были показы:
                        //if (($item >= $stat_from) && ($item <= $stat_to)) {
                        //if (($item >= $stat_from)) {
                        if (($item <= $stat_to)) {
                            $period[] = $day_item;
                            if ($stats[$day_item]) {
                                AddDataStats($dataStats, $stats[$day_item]);
                            } else {
                                AddDataStatsNull($dataStats, $stat_cats);
                            }
                        }
                    }
                }

                $dataStats['period'] = $period;
            }
        }
        
        return $dataStats;
    }
    
    // Данные для статистики кампании по сайтам
    public function getCampaignsSitesStat($type, $id, $taget_action, $dates)
    {
        if ($type == 'campaign') {
            $method = 'camp_zone';
        } else {
            $method = 'cgroup_zone';
        }
        
        $dataRequest = array(
            'method' => $method,
            'data' => array(
                'id' => $id,
                'start_date' => $dates[0],
                'end_date' => $dates[1]
            )      
        );
        
        //return $dataRequest;
        try {
            $stats = $this->apiRequest($dataRequest);
        } catch (\Exception $e) {
            $stats['status'] = 'Error';
            return $stats;
        }
        //return $stats;
        
        if ($stats) {
            
            foreach ($stats as $site => $stat) {
                $this->AddSpecialFields($stats[$site]);
                if ($stat['sub']) {
                    foreach ($stat['sub'] as $sub => $stat) {
                        $this->AddSpecialFields($stats[$site]['sub'][$sub]);
                    }
                }
            }
            
            $dataStats = $stats;
        }
        
        return $dataStats;
    }
            
    // Данные для статистики кампании по регионам
    public function getCampaignsRegionsStat($type, $id, $taget_action, $dates)
    {
        if ($type == 'campaign') {
            $method = 'camp_geo';
        } else {
            $method = 'cgroup_geo';
        }
        
        $dataRequest = array(
            'method' => $method,
            'data' => array(
                'id' => $id,
                'start_date' => $dates[0],
                'end_date' => $dates[1]
            )      
        );
        
        //return $dataRequest;
        try {
            $stats = $this->apiRequest($dataRequest);
        } catch (\Exception $e) {
            $stats['status'] = 'Error';
            return $stats;
        }
        //return $stats;
        
        if ($stats) {
            foreach ($stats as $region => $stat) {
                $this->AddSpecialFields($stats[$region]);
                
                if ($stat['sub']) {
                    foreach ($stat['sub'] as $sub => $stat) {
                        $this->AddSpecialFields($stats[$region]['sub'][$sub]);
                    }
                }
            }
            $dataStats = $stats;
        }
        
        return $dataStats;
    }
    
    
    
    // Запрос к API:
    private function apiRequest($data) 
    {

        $playload = json_encode($data);
        
        $url = 'http://stat.instraroam.net/json/'.md5($playload . $this->hashSolt);
        //$url = 'https://9261bdc7.ngrok.io/json/'.md5($playload . $this->hashSolt);
        
        $cl = curl_init();
        curl_setopt($cl, CURLOPT_URL, $url);
        curl_setopt($cl, CURLOPT_POST, true);
        curl_setopt($cl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($cl, CURLOPT_HTTPHEADER, array(
            'Content-Type:application/json'
        ));        
        curl_setopt($cl, CURLOPT_POSTFIELDS, $playload);
        
        $result = curl_exec($cl);
        $info = curl_getinfo($cl);
        curl_close($cl);
        
        if($info['http_code'] != 200) {
            throw new \Exception('Error. ' . $info['http_code']);
        }
        
        return json_decode($result, 1);
    }
    
}
