<?php defined('ABSPATH') or die("you do not have acces to this page!");
if (!class_exists('cmplz_statistics')) {
    class cmplz_statistics
    {
        private static $_this;
        public $prefix;

        function __construct()
        {
            if (isset(self::$_this))
	            wp_die(sprintf('%s is a singleton class and you cannot create a second instance.', get_class($this)));
            self::$_this = $this;


            add_action('activated_plugin', array($this, 'update_db_check'), 10, 2);
            add_action('admin_init', array($this, 'update_db_check'), 10);
            add_action("admin_enqueue_scripts", array($this, "enqueue_scripts"));

            add_filter('cmplz_user_banner_id', array($this, 'get_user_banner_id'));
            add_filter('cmplz_user_data', array($this, 'get_user_data'));
            add_action('cmplz_track_status', array($this, 'track_status'));

            add_action('complianz_before_save_settings_option', array($this, 'init_statistics_on_settings_change'), 10, 4);

            add_action('wp_ajax_cmplz_archive_cookiebanner', array($this, 'archive_cookiebanner'));
            add_action('wp_ajax_cmplz_restore_cookiebanner', array($this, 'restore_cookiebanner'));

            add_action('cmplz_before_cookiebanner_list', array($this, 'notices'));
            add_action('cmplz_before_cookiebanner_list', array($this, 'graph'));

            add_action('cmplz_after_cookiebanner_title', array($this, 'after_cookiebanner_title'));

            add_filter('cmplz_ab_testing_enabled', array($this, 'ab_testing_enabled'));

            add_filter('cmplz_cookiebanner_name', array($this, 'cookiebanner_name'));
            add_filter('cmplz_default_only', array($this,'default_only'));
            add_filter('cmplz_show_cookiebanner_list_view', array($this,'show_cookiebanner_list_view'));
        }

        static function this()
        {
            return self::$_this;
        }


        /**
         * Override the showing of the list view for banners
         * @hooked cmplz_show_cookiebanner_list_view
         * @param $show
         * @return bool
         */

        public function show_cookiebanner_list_view($show){
            return true;
        }

        public function default_only($default_only){
            return !COMPLIANZ::$cookie_admin->ab_testing_enabled();
        }

        public function cookiebanner_name($name){
            if ($this->best_performer_enabled()) {
                $name .= '<br>'.__('Because this variation was determined to get the best results, this cookie warning was enabled as your default cookie warning', 'complianz-gdpr');
            }
            return $name;
        }

        /**
         * Override free function to enable a/b testing when active
         * @param $enabled
         * @return bool $enabled
         *
         */

        public function ab_testing_enabled($enabled)
        {
            return cmplz_get_value('a_b_testing');
        }

        /**
         * In free, we have only one cookie banner, so we don't show the add banner and reset stats options
         * In premium we show all banners, the user can click to a subpage.
         */
        public function after_cookiebanner_title()
        {
            //if geoip is not used, we only have one cookie banner, so go straight to the edit page.
            if (COMPLIANZ::$cookie_admin->ab_testing_enabled()) { ?>
                <a href="<?php echo admin_url('admin.php?page=cmplz-cookiebanner&action=new'); ?>"
                   class="page-title-action"><?php _e('Add banner', 'complianz-gdpr') ?></a>
                <a href="<?php echo admin_url('admin.php?page=cmplz-cookiebanner&action=reset_statistics'); ?>"
                   class="page-title-action cmplz-reset"><?php _e('Reset statistics', 'complianz-gdpr') ?></a>
            <?php }
        }

        /**
         * Restore a cookiebanner
         * @hooked wp_ajax_cmplz_restore_cookiebanner
         */

        public function restore_cookiebanner()
        {

            if (!current_user_can('manage_options')) return;

            if (isset($_POST['banner_id'])) {

                $banner = new CMPLZ_COOKIEBANNER(intval($_POST['banner_id']));
                $banner->restore();

                $response = json_encode(array(
                    'success' => true,
                ));

                header("Content-Type: application/json");
                echo $response;
                exit;
            }
        }




        /* Initialize the statistics if the ab setting is changed
            This ensures the data is cleared on disabling, and sets the start time on enabling.
         */

        public function init_statistics_on_settings_change($fieldname, $fieldvalue, $prev_value, $type)
        {


            if ($fieldvalue === $prev_value) return;

            if ($fieldname == 'a_b_testing') {
                $this->init_statistics();
                cmplz_update_banner_version_all_banners();
            }
        }

        public function init_statistics()
        {
            if (!current_user_can('manage_options')) return;

            update_option('cmplz_tracking_ab_started', time());
            update_option('cmplz_enabled_best_performer', false);

            //update banner version for all banners

            global $wpdb;
            //reset the data
            $wpdb->query("TRUNCATE TABLE {$wpdb->prefix}cmplz_statistics");
        }


        /**
         * If ab testing is enabled, and the plugin has been tracking for more than a month, the best performing banner will get selected as default banner.
         *
         *
         * */


        public function cron_maybe_enable_best_performer()
        {
            if (!COMPLIANZ::$cookie_admin->ab_testing_enabled()) return;

            if ($this->seconds_left_ab_tracking()>0) {
                return;
            }

            //testing is currently enabled, and we have been testing more than a month. Time to set the best performing one, and disable tracking.
            $best_performer = $this->best_performing_cookiebanner();
            if ($best_performer) {
                $banner = new CMPLZ_COOKIEBANNER($best_performer);
                $banner->default = true;
                $banner->save();
                $this->init_statistics();
            }

            //disable tracking
            $cookie_settings = get_option('complianz_options_settings');
            $cookie_settings['a_b_testing'] = false;
            update_option('complianz_options_settings', $cookie_settings);


            //store this change
            update_option('cmplz_enabled_best_performer', true);

        }


        /**
         * In case of ab testing, the user data called through ajax overrides the default cookie setting data.
         * This way, even with caching, the data can be loaded dynamically.
         *
         * */

        public function get_user_data()
        {
            if (!COMPLIANZ::$cookie_admin->ab_testing_enabled()) return array();
            $user_banner_id = $this->get_user_banner_id();

            $data = COMPLIANZ::$cookie_admin->get_cookiebanner_settings($user_banner_id);
            return $data;
        }

        /**
         *
         * For a/b testing, get a random banner id. If the user visited before, get that same banner id.
         * @return int banner_id
         */

        public function get_user_banner_id()
        {

            if (!COMPLIANZ::$cookie_admin->ab_testing_enabled()) {
                return cmplz_get_default_banner_id();
            }

            $banners = wp_list_pluck(cmplz_get_cookiebanners(), 'ID');
            $random_key = array_rand($banners);
            $random = $banners[$random_key];
            $user_banner_id = 0;
            global $wpdb;

            if (isset($_COOKIE['cmplz_id'])) {
                $visitor_id = intval($_COOKIE['cmplz_id']);
                $user_banner_id = $wpdb->get_var($wpdb->prepare("SELECT cookiebanner_id from {$wpdb->prefix}cmplz_statistics WHERE ID = %s", $visitor_id));
                //check if this variation still exists
                if (!in_array($user_banner_id, $banners)) {
                    $user_banner_id = $random;
                    $success = $wpdb->update($wpdb->prefix . 'cmplz_statistics',
                        array('cookiebanner_id' => $user_banner_id),
                        array('ID' => $visitor_id)
                    );
                    //if the update failed, the user wasn't found in the database, so we insert it fresh
                    if ($success === 0) {
                        $user_banner_id = 0;
                    }
                }
            }

            if ($user_banner_id == 0) {

                $user_banner_id = $random;
                $wpdb->insert($wpdb->prefix . 'cmplz_statistics',
                    array('cookiebanner_id' => $user_banner_id)
                );
                $visitor_id = $wpdb->insert_id;
                setcookie('cmplz_id', $visitor_id, time() + (DAY_IN_SECONDS * 365), '/');
            }

            return $user_banner_id;
        }


        public function update_db_check()
        {
            if (get_option('cmplz_statsdb_version') != cmplz_version) {

                require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
                global $wpdb;
                $charset_collate = $wpdb->get_charset_collate();

                $table_name = $wpdb->prefix . 'cmplz_statistics';
                $sql = "CREATE TABLE $table_name (
                  `ID` int(11) NOT NULL AUTO_INCREMENT,
                  `region` varchar(255) NOT NULL,
                  `pageviews` int(11) NOT NULL,
                  `consenttype` varchar(255) NOT NULL,
                  `status` varchar(255) NOT NULL,
                  `cookiebanner_id` int(11) NOT NULL,
                  PRIMARY KEY  (ID)
                ) $charset_collate;";

                dbDelta($sql);

                update_option('cmplz_statsdb_version', cmplz_version);
            }
        }





        /**
         * Archive a cookiebanner
         * @hooked wp_ajax_cmplz_archive_cookiebanner
         */

        public function archive_cookiebanner()
        {
            if (!current_user_can('manage_options')) return;

            if (isset($_POST['banner_id'])) {
                $banner_id = intval($_POST['banner_id']);

                $banner = new CMPLZ_COOKIEBANNER($banner_id);
                $banner->archive();

                $response = json_encode(array(
                    'success' => true,
                ));

                header("Content-Type: application/json");
                echo $response;
                exit;
            }
        }


        /**
         * Each page page_view, we check if this user was already listed
         * By checking the cookie. No usage data is stored, so we don't need to have a cookie warning for this
         * If user was not listed before, we add a new entry
         *
         * */

        public function track_status()
        {

            $status = isset($_GET['status']) ? sanitize_title($_GET['status']) : 'no-choice';

            //backward compatibility. Todo: change all into marketing
	        if ($status==='marketing') $status = 'all';
            $consenttype = isset($_GET['consenttype']) ? sanitize_title($_GET['consenttype']) : COMPLIANZ::$company->get_default_consenttype();
            $visitor_is_registered = true;
            global $wpdb;
            if (isset($_COOKIE['cmplz_id'])) {
                $visitor_id = intval($_COOKIE['cmplz_id']);
                //we increase pageviews, as a way to make sure the data is changed even when the status has not changed.
                //if we do not do this, the user will be added twice, as success will return 0
                $pageviews = intval($wpdb->get_var($wpdb->prepare("select pageviews from {$wpdb->prefix}cmplz_statistics where ID = %s", $visitor_id)));
                $pageviews++;
                $success = $wpdb->update($wpdb->prefix . 'cmplz_statistics',
                    array(
                        'status' => $status,
                        'pageviews' => $pageviews,
                        'consenttype' => $consenttype
                    ),
                    array('ID' => $visitor_id)
                );

                //check if any rows were affected. If not, this entry might have been deleted.
                if ($success === 0) {
                    $visitor_is_registered = false;
                }
            } else {
                $visitor_is_registered = false;
            }

            if (!$visitor_is_registered) {
                $wpdb->insert($wpdb->prefix . 'cmplz_statistics',
                    array('status' => $status, 'consenttype' => $consenttype)
                );
                $visitor_id = $wpdb->insert_id;

                setcookie('cmplz_id', $visitor_id, time() + (DAY_IN_SECONDS * 365), '/');

            }
        }

        /**
         * Get the best performing cookiebanner
         * @return bool
         */

        public function best_performing_cookiebanner()
        {
            $banners = cmplz_get_cookiebanners();
            $best_performer_percentage = 0;
            $best_performer = false;
            foreach ($banners as $banner) {
                $banner = new CMPLZ_COOKIEBANNER($banner->ID);
                $p = $banner->conversion_percentage('all');

                if ($p > $best_performer_percentage) {
                    $best_performer_percentage = $p;
                    $best_performer = $banner->id;
                }

            }

            return $best_performer;
        }


        /**
         * Get cookie banner variations
         * Used for upgrade procedure
         * @deprecated
         * @return array
         */

        public function get_variations()
        {
            $variations = array();

            global $wpdb;
            $result = $wpdb->query("SHOW TABLES LIKE '{$wpdb->prefix}cmplz_variations'");
            if (empty($result)) {
                return array();
            }


            if (COMPLIANZ::$cookie_admin->ab_testing_enabled()) {
                global $wpdb;
                $results = $wpdb->get_results("select ID from {$wpdb->prefix}cmplz_variations as v where v.default != true AND v.title != 'migrated'");
                $variations = wp_list_pluck($results, 'ID');
                array_unshift($variations, '');
            }

            return $variations;
        }


        /**
         * Get a human readable name for the variation
         * Used for upgrade procedure
         * @deprecated
         * @param string $variation_id
         * @return string
         */

        public function get_variation_nicename($variation_id)
        {

            global $wpdb;
            $result = $wpdb->query("SHOW TABLES LIKE '{$wpdb->prefix}cmplz_variations'");
            if (empty($result)) {
                return '';
            }

            global $wpdb;
            if ($variation_id == '') {
                $title = $wpdb->get_var("select title from {$wpdb->prefix}cmplz_variations as v where v.default = TRUE");
            } else {
                $title = $wpdb->get_var($wpdb->prepare("select title from {$wpdb->prefix}cmplz_variations where ID = %s", $variation_id));
            }
            return $title;
        }

        /**
         * Get the total number of seconds still left in this ab tracking test
         * @return int
         * @since 2.0.0
         *
         */

        public function seconds_left_ab_tracking()
        {
            if ($this->best_performer_enabled()) {
                return 0;
            }

            $start_date = get_option('cmplz_tracking_ab_started');

            $testing_duration = apply_filters('cmplz_ab_testing_duration', cmplz_get_value('a_b_testing_duration')) * DAY_IN_SECONDS;
            $now = time();
            $time_since = $now - $start_date;

            $seconds_left = $testing_duration - $time_since;
            if ($seconds_left <0 ) $seconds_left = 0;

            return $seconds_left;
        }

        /**
         * Get the time left in the current A/B test, human readable format.
         * @since 2.0
         * @return array|int
         */

        public function time_left_ab_tracking()
        {
            if (get_option('cmplz_enabled_best_performer')) {
                return 0;
            }

            $start_date = get_option('cmplz_tracking_ab_started');


            $testing_duration = apply_filters('cmplz_ab_testing_duration', cmplz_get_value('a_b_testing_duration'));
            $now = time();

            $current_duration_days = round(($now - $start_date) / DAY_IN_SECONDS, 2);
            $days_left = $testing_duration - $current_duration_days;

            $days = round($days_left - 0.499);

            $hours = (($days_left - $days) * DAY_IN_SECONDS) / HOUR_IN_SECONDS;
            $time_left = array('days' => $days, "hours" => $hours);

            return $time_left;
        }


        /**
         * Get a nice label for a status
         * @since 2.0
         * @param $status
         * @param string $variation_id
         * @return string $label
         */

        public function get_status_label($status, $variation_id = '')
        {

            switch ($status) {
                case 'no-choice':
                    return __('No choice', 'complianz-gdpr');
                case 'no-warning':
                    return __('No warning', 'complianz-gdpr');
                case 'all':
                    return __('Full consent', 'complianz-gdpr');
                case 'stats':
                    return __('Statistics', 'complianz-gdpr');
                case 'functional':
                    return __('Functional', 'complianz-gdpr');
            }


            if (COMPLIANZ::$cookie_admin->tagmamanager_fires_scripts()) {
                $cats = cmplz_get_value('tagmanager_categories' . $variation_id);
                $categories = explode(',', $cats);
                foreach ($categories as $index => $category) {
                    if (intval(str_replace('cmplz_event_', '', $status)) == $index) {
                        return $category;
                    }
                }
            }

            return $status;
        }


        /**
         * Check if the best performer is enabled
         *
         * @since 2.0
         * @return bool $enabled;
         */

        public function best_performer_enabled()
        {
            return get_option('cmplz_enabled_best_performer');
        }


        /**
         * Notices about statistics
         */

        public function notices()
        {
            //create a dataset which includes each variation, and all labels stacked.
            if (!COMPLIANZ::$cookie_admin->site_needs_cookie_warning()) return;

            ?>

            <p>
                <?php
                $notice = __('The conversion graph shows the ratio for the different choices users have. When a user has made a choice, this will be counted as either a converted user, or a not converted. If no choice is made, the user will be listed in the "No choice" category.', 'complianz-gdpr');
                $notice .= '&nbsp;';
                if (cmplz_geoip_enabled()) {
                    $enabled_regions = implode(", ", cmplz_get_regions());
                    $notice .= sprintf(__('As you have enabled geoip, there are several regions in which a banner is shown, in different ways. In regions apart from %s no banner is shown at all.', 'complianz-gdpr'), $enabled_regions);
                }

                cmplz_notice($notice);
                ?>
            </p>
            <p>
                <?php
                $a_b_testing = COMPLIANZ::$cookie_admin->ab_testing_enabled();

                //it's no use showing this message when only one banner is available.
                $banners = cmplz_get_cookiebanners();
                if (count($banners)>1 && $a_b_testing && !$this->best_performer_enabled()) {
                    if ($this->seconds_left_ab_tracking() > 0) {
                        $time = $this->time_left_ab_tracking();

                        $days_string = sprintf(_n('%s day', '%s days', $time['days'], 'complianz-gdpr'), number_format_i18n($time['days']));
                        $hours_string = sprintf(_n('%s hour', '%s hours', $time['hours'], 'complianz-gdpr'), number_format_i18n($time['hours']));

                        cmplz_notice(sprintf(__('A/B tracking is still in progress, in approximately %s and %s the application will automatically enable the best performing banner.', 'complianz-gdpr'), $days_string, $hours_string), 'warning');
                    } else {
                        cmplz_notice(__('The A/B tracking period has ended, the best performer will be enabled on the next scheduled check.', 'complianz-gdpr'));
                    }
                }

                ?>
            </p>
            <?php
        }

        /**
         * enqueue the scripts for the backend
         * @param $hook
         */


        public function enqueue_scripts($hook)
        {
            if ((strpos($hook, 'complianz') === FALSE) && strpos($hook, 'cmplz') === FALSE) return;
            /*Graphs*/
            wp_enqueue_script('apex', cmplz_url . 'assets/apexcharts/apexcharts.min.js', array('jquery',), cmplz_version, false);

            $min = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min';

            wp_enqueue_script('cmplz_statistics', cmplz_url . "pro/assets/js/statistics$min.js", array('jquery'), cmplz_version, true);

            wp_localize_script(
                'cmplz_statistics',
                'cmplz_statistics',
                array(
                    'admin_url' => admin_url('admin-ajax.php'),
                    'translations' => array(
                        'delete' => __('Delete', 'complianz-gdpr'),
                    )
                )
            );

        }

        /**
         * Show statistics in a graph
         */

        public function graph()
        {

            //if a/b testing is disabled, hide the graph
            if (!COMPLIANZ::$cookie_admin->ab_testing_enabled()) return;

            //if no cookie warning is needed, no a/b testing is needed either
            if (!COMPLIANZ::$cookie_admin->site_needs_cookie_warning()) return;

            $args = array();
            if (!COMPLIANZ::$cookie_admin->ab_testing_enabled()) {
                $args['default'] = true;
            }
            $banners = cmplz_get_cookiebanners($args);

            ?>
            <table class="cmplz-graph-container">
                <?php
                $options = array();
                $consenttypes['all'] = "all";

                $consenttypes = $consenttypes + cmplz_get_used_consenttypes();
                foreach ($consenttypes as $consenttype) {
                    foreach ($banners as $banner) {
                        $total = 0;
                        $variation_options = array();
                        $banner = new CMPLZ_COOKIEBANNER($banner->ID);

                        $statuses = $banner->get_statuses(false, $consenttype);
                        foreach ($statuses as $status) {
                            $count = $banner->get_count($status, $consenttype);
                            $total += $count;
                            $variation_options[] = array(
                                'label' => $this->get_status_label($status, $banner->id),
                                'value' => $count,
                                'key' => sanitize_title($this->get_status_label($status, $banner->id)),
                            );
                        }

                        $title = $banner->title;
                        if (COMPLIANZ::$cookie_admin->ab_testing_enabled() && $this->best_performing_cookiebanner() === $banner->id) {
                            $title .= " " . __("(best performer)", 'complianz-gdpr');
                        }

                        $options[$consenttype][$banner->id] = array(
                            'label' => $title,
                            'data' => $variation_options,
                            'total' => $total,
                        );


                    }
                }

                if (isset($options['all'])) {
                    ?>
                    <tr class="row">
                        <th>&nbsp;</th>
                        <td class="column">
                            <div>

                                <select name="cmplz_region">
                                    <?php foreach ($consenttypes as $consenttype) { ?>
                                        <option value="<?php echo $consenttype ?>"><?php echo cmplz_consenttype_nicename($consenttype) ?></option>
                                    <?php } ?>
                                </select>

                                <select name="stats_type">
                                    <option value="pct"><?php _e('Percentage', 'complianz-gdpr') ?></option>
                                    <option value="nrs"><?php _e('Count', 'complianz-gdpr') ?></option>
                                </select>
                            </div>
                            <?php
                            $this->bar($options['all'], 'pct', 'all');
                            $this->bar($options['all'], 'nrs', 'all');

                            foreach ($consenttypes as $consenttype) {
                                $this->bar($options[$consenttype], 'pct', $consenttype);
                                $this->bar($options[$consenttype], 'nrs', $consenttype);
                            }

                            ?>

                        </td>

                    </tr>
                    <?php
                }
                ?>
            </table>
            <?php
        }


        /**
         * Generate a horizontal bar graph
         * @param $options
         * @param $type
         * @param $region
         */

        public function bar($options, $type, $consenttype)
        {
            $has_data = false;
            foreach ($options as $option) {
                if ($option['total'] > 0) {
                    $has_data = true;
                }
            }

            if (!$has_data) {
                ?>
                <p class="hidden"><?php _e('There is not enough data yet to show a graph.', 'complianz-gdpr') ?></p>
                <?php
            } else {
                $graph_id = 'bar_' . $type . '_' . $consenttype;

                echo '<div id="' . $graph_id . '_container" class="graph_container hidden" >';

                //merge all keys from the different arrays
                $statuses = array();
                foreach ($options as $option) {
                    foreach ($option['data'] as $data) {
                        if (!in_array($data['label'], $statuses)) {
                            $statuses[$data['key']] = $data['label'];
                        }
                    }
                }
                $bar_height = (count($options)*80<300) ? 300 : count($options)*80;
                ?>
                <div id="<?php echo $graph_id ?>" class="ctb-bar"
                     style="height: <?php echo $bar_height?>px; width:550px;"></div>
                <script>

                    var options = {
                        chart: {
                            height: <?php echo $bar_height?>,
                            type: 'bar',
                            stacked: true,
                        },
                        plotOptions: {
                            bar: {
                                horizontal: true,
                            },

                        },
                        stroke: {
                            width: 1,
                            colors: ['#fff']
                        },
                        series: [
                            <?php
                            foreach ($statuses as $status_key => $status) {
                                echo '{';
                                echo "name: '" . $status . "',"; //status
                                echo PHP_EOL;


                                echo "data: [";
                                $values = array();
                                foreach ($options as $banner_id => $banner) {
                                    $total = $banner['total'];
                                    if ($total == 0) $total = 1;
                                    foreach ($banner['data'] as $data) {
                                        if ($data['key'] !== $status_key) continue;
                                        $values[] = ($type == 'pct') ? round( (100*$data['value'] / $total), 0) : $data['value'];
                                    }

                                }
                                echo implode(",", $values);
                                echo "]";
                                echo PHP_EOL;
                                echo '},';
                            }
                            ?>
                        ],
                        title: {
                            text: ''
                        },
                        xaxis: {
                            categories: [<?php foreach($options as $banner_id => $banner){
                                echo "'" . $banner['label'] . "', ";
                            }?>],
                            labels: {
                                formatter: function (val) {
                                    return Math.round(val)
                                }
                            }
                        },
                        yaxis: {
                            title: {
                                text: undefined
                            },

                        },
                        tooltip: {
                            x: {
                                show: false
                            },
                            y: {
                                formatter: function (val) {
                                    return val
                                }
                            }
                        },
                        fill: {
                            opacity: 1

                        },

                        legend: {
                            position: 'top',
                            horizontalAlign: 'left',
                            offsetX: 40
                        }
                    };
                    var chart = new ApexCharts(
                        document.querySelector("#<?php echo $graph_id?>"),
                        options
                    );

                    chart.render();


                </script>
                </div>
                <?php
            }
        }


    } //class closure
}
