<?php

namespace WP_STATISTICS;

use WP_Statistics\Service\Analytics\VisitorProfile;

class Pages
{
    /**
     * Check Active Record Pages
     *
     * @return mixed
     */
    public static function active()
    {
        return (has_filter('wp_statistics_active_pages')) ? apply_filters('wp_statistics_active_pages', true) : 1;
    }

    /**
     * Get WordPress Page Type
     */
    public static function get_page_type()
    {

        //Set Default Option
        $current_page = array("type" => "unknown", "id" => 0, "search_query" => '');

        //Check Query object
        $id = get_queried_object_id();
        if (is_numeric($id) and $id > 0) {
            $current_page['id'] = $id;
        }

        //WooCommerce Product
        if (class_exists('WooCommerce')) {
            if (is_product()) {
                return wp_parse_args(array("type" => "product"), $current_page);
            }
            if (is_shop()) {
                // Get Shop Page ID
                $shopPageID = wc_get_page_id('shop');

                // Set current page id
                $current_page['id'] = $shopPageID;

                // Return Page Type
                return wp_parse_args(array("type" => "page"), $current_page);
            }
        }

        //Home Page or Front Page
        if (is_front_page() || is_home()) {
            return wp_parse_args(array("type" => "home"), $current_page);
        }

        //attachment View
        if (is_attachment()) {
            $current_page['type'] = "attachment";
        }

        //is Archive Page
        if (is_archive()) {
            $current_page['type'] = "archive";
        }

        //Single Post From All Post Type
        if (is_singular()) {
            $post_type = get_post_type();
            if ($post_type != 'post') {
                $post_type = 'post_type_' . $post_type;
            }
            $current_page['type'] = $post_type;
        }

        //Single Page
        if (is_page()) {
            $current_page['type'] = "page";
        }

        //Category Page
        if (is_category()) {
            $current_page['type'] = "category";
        }

        //Tag Page
        if (is_tag()) {
            $current_page['type'] = "post_tag";
        }

        //is Custom Term From Taxonomy
        if (is_tax()) {
            $term                 = get_queried_object();
            $current_page['type'] = 'tax_' . $term->taxonomy;
        }

        //is Author Page
        if (is_author()) {
            $current_page['type'] = "author";
        }

        //is search page
        $search_query = sanitize_text_field(get_search_query(false));
        if (trim($search_query) != "") {
            return array("type" => "search", "id" => 0, "search_query" => $search_query);
        }

        //is 404 Page
        if (is_404()) {
            $current_page['type'] = "404";
        }

        // Add WordPress Feed
        if (is_feed()) {
            $current_page['type'] = "feed";
        }

        // Add WordPress Login Page
        if (Helper::is_login_page()) {
            $current_page['type'] = "loginpage";
        }

        return apply_filters('wp_statistics_current_page', $current_page);
    }

    /**
     * Get Page Url
     *
     * @return bool|mixed|string
     */
    public static function get_page_uri()
    {

        // Get the site's path from the URL.
        $site_uri     = wp_parse_url(site_url(), PHP_URL_PATH);
        $site_uri_len = strlen($site_uri ? $site_uri : '');

        // Get the site's path from the URL.
        $home_uri     = wp_parse_url(home_url(), PHP_URL_PATH);
        $home_uri_len = strlen($home_uri ? $home_uri : '');

        // Get the current page URI.
        $page_uri = sanitize_url(wp_unslash($_SERVER["REQUEST_URI"]));

        /*
         * We need to check which URI is longer in case one contains the other.
         * For example home_uri might be "/site/wp" and site_uri might be "/site".
         * In that case we want to check to see if the page_uri starts with "/site/wp" before
         * we check for "/site", but in the reverse case, we need to swap the order of the check.
         */
        if ($site_uri_len > $home_uri_len) {
            if (substr($page_uri, 0, $site_uri_len) == $site_uri) {
                $page_uri = substr($page_uri, $site_uri_len);
            }

            if (substr($page_uri, 0, $home_uri_len) == $home_uri) {
                $page_uri = substr($page_uri, $home_uri_len);
            }
        } else {
            if (substr($page_uri, 0, $home_uri_len) == $home_uri) {
                $page_uri = substr($page_uri, $home_uri_len);
            }

            if (substr($page_uri, 0, $site_uri_len) == $site_uri) {
                $page_uri = substr($page_uri, $site_uri_len);
            }
        }

        // Sanitize the page URI.
        $page_uri = sanitize_url($page_uri);

        // If we're at the root (aka the URI is blank), let's make sure to indicate it.
        if ($page_uri == '') {
            $page_uri = '/';
        }

        return apply_filters('wp_statistics_page_uri', $page_uri);
    }

    /**
     * Sanitize Page Url For Push to Database
     * @param $visitorProfile VisitorProfile
     */
    public static function sanitize_page_uri($visitorProfile)
    {

        // Get Current WordPress Page
        $current_page = $visitorProfile->getCurrentPageType();

        // Get the current page URI.
        $page_uri = Pages::get_page_uri();

        // Get String Search WordPress
        if (array_key_exists("search_query", $current_page) and !empty($current_page["search_query"])) {
            $page_uri = "?s=" . $current_page['search_query'];
        }

        // Sanitize for WordPress Login Page
        if ($current_page['type'] == "loginpage") {
            $page_uri = Helper::RemoveQueryStringUrl($page_uri);
        }

        // Check Strip Url Parameter
        if (array_key_exists("search_query", $current_page) === false) {
            $temp = explode('?', $page_uri);
            if ($temp !== false) {
                $page_uri = $temp[0];
            }
        }

        // Filter query parameters based on allowed query params list
        $page_uri = Helper::FilterQueryStringUrl($page_uri, Helper::get_query_params_allow_list());

        // Limit the URI length to 255 characters, otherwise we may overrun the SQL field size.
        return substr($page_uri, 0, 255);
    }

    /**
     * Record Page in Database
     * @param VisitorProfile $visitorProfile
     */
    public static function record($visitorProfile)
    {
        global $wpdb;

        // Get Current WordPress Page
        $current_page = $visitorProfile->getCurrentPageType();

        // If we didn't find a page id, we don't have anything else to do.
        if ($current_page['type'] == "unknown" || !isset($current_page['id'])) {
            return false;
        }

        // Get Page uri
        $page_uri = self::sanitize_page_uri($visitorProfile);

        // If the length of URI is more than 190 characters
        // Crop it, so it can be stored in the database
        if (strlen($page_uri) > 190) {
            $page_uri = substr($page_uri, 0, 190);
        }

        // Check if we have already been to this page today.
        $search_query = array_key_exists("search_query", $current_page) === true ? $wpdb->prepare("AND `uri` = %s", $page_uri) : "";
        $tablePage    = DB::table('pages');

        $query = $wpdb->prepare(
            "SELECT `page_id` FROM `{$tablePage}` WHERE `date` = %s {$search_query} AND `type` = %s AND `id` = %d",
            TimeZone::getCurrentDate('Y-m-d'),
            $current_page['type'],
            $current_page['id']
        );
        $exist = $wpdb->get_row($query, ARRAY_A);

        // Update Exist Page
        if (null !== $exist) {
            $query = $wpdb->prepare("UPDATE `{$tablePage}` SET `count` = `count` + 1 WHERE `date` = %s {$search_query} AND `type` = %s AND `id` = %d",
                TimeZone::getCurrentDate('Y-m-d'),
                $current_page['type'],
                $current_page['id']
            );

            $wpdb->query($query);
            $page_id = $exist['page_id'];

        } else {

            // Prepare Pages Data
            $pages = array(
                'uri'   => $page_uri,
                'date'  => TimeZone::getCurrentDate('Y-m-d'),
                'count' => 1,
                'id'    => $current_page['id'],
                'type'  => $current_page['type']
            );
            $pages = apply_filters('wp_statistics_pages_information', $pages);

            // Added to DB
            $page_id = self::save_page($pages);
        }

        return (isset($page_id) ? $page_id : false);
    }

    /**
     * Add new row to Pages Table
     *
     * @param array $page
     * @return int
     */
    public static function save_page($page = array())
    {
        global $wpdb;

        # Add Filter Insert ignore
        add_filter('query', array('\WP_STATISTICS\DB', 'insert_ignore'), 10);

        # Save to WordPress Database
        $insert = $wpdb->insert(
            DB::table('pages'),
            $page
        );
        if (!$insert) {
            if (!empty($wpdb->last_error)) {
                \WP_Statistics::log($wpdb->last_error, 'warning');
            }
        }

        # Get Page ID
        $page_id = $wpdb->insert_id;

        # Remove ignore filter
        remove_filter('query', array('\WP_STATISTICS\DB', 'insert_ignore'), 10);

        # Do Action After Save New Visitor
        do_action('wp_statistics_save_page', $page_id, $page);

        return $page_id;
    }

    /**
     * Get Page information
     *
     * @param $page_id
     * @param string $type
     * @return array
     */
    public static function get_page_info($page_id, $type = 'post', $slug = false)
    {

        //Create Empty Object
        $arg      = array();
        $defaults = array(
            'link'      => $slug,
            'edit_link' => '',
            'object_id' => $page_id,
            'title'     => '-',
            'report'    => Menus::admin_url('content-analytics', ['type' => 'single-resource', 'uri' => rawurlencode($slug)]),
            'meta'      => array()
        );
        if (strpos($type, 'tax_') === 0) {
            $type = 'tax';
        }

        if (!empty($type)) {
            switch ($type) {
                case "product":
                case "attachment":
                case "post":
                case "page":
                    $arg = array(
                        'title'     => get_the_title($page_id),
                        'link'      => get_the_permalink($page_id),
                        'edit_link' => get_edit_post_link($page_id),
                        'report'    => Menus::admin_url('content-analytics', ['type' => 'single', 'post_id' => $page_id]),
                        'meta'      => array(
                            'post_type' => get_post_type($page_id)
                        )
                    );
                    break;
                case "category":
                case "post_tag":
                case "tax":
                    $term = get_term($page_id);
                    if (!is_wp_error($term) and $term !== null) {
                        $arg = array(
                            'title'     => esc_html($term->name),
                            'link'      => (is_wp_error(get_term_link($page_id)) === true ? '' : get_term_link($page_id)),
                            'edit_link' => get_edit_term_link($page_id),
                            'report'    => Menus::admin_url('category-analytics', ['type' => 'single', 'term_id' => $term->term_taxonomy_id]),
                            'meta'      => array(
                                'taxonomy'         => $term->taxonomy,
                                'term_taxonomy_id' => $term->term_taxonomy_id,
                                'count'            => $term->count
                            )
                        );
                    }
                    break;
                case "home":
                    $arg = array(
                        'title' => $page_id ? sprintf(__('Home Page: %s', 'wp-statistics'), get_the_title($page_id)) : __('Home Page', 'wp-statistics'),
                        'link'  => get_site_url(),
                        'meta'  => array(
                            'post_type' => get_post_type($page_id)
                        )
                    );

                    if ($page_id) {
                        $arg['report'] = Menus::admin_url('content-analytics', ['type' => 'single', 'post_id' => $page_id]);
                    }
                    break;
                case "author":
                    $user_info = get_userdata($page_id);
                    $arg       = array(
                        'title'     => ($user_info->display_name != "" ? esc_html($user_info->display_name) : esc_html($user_info->first_name . ' ' . $user_info->last_name)),
                        'link'      => get_author_posts_url($page_id),
                        'edit_link' => get_edit_user_link($page_id),
                        'report'    => Menus::admin_url('author-analytics', ['type' => 'single-author', 'author_id' => $user_info->ID]),
                        'meta'      => [
                            'author_id' => $user_info->ID
                        ]
                    );
                    break;
                case "feed":
                    $arg['title'] = __('Feed', 'wp-statistics');
                    break;
                case "loginpage":
                    $arg['title'] = __('Login Page', 'wp-statistics');
                    break;
                case "search":
                    $arg['title'] = __('Search Page', 'wp-statistics');
                    break;
                case "404":
                    $arg['title'] = sprintf(__('404 not found (%s)', 'wp-statistics'), esc_html(substr($slug, 0, 20)));
                    break;
                case "archive":
                    if ($slug) {
                        $post_type   = trim($slug, '/');
                        $post_object = get_post_type_object($post_type);

                        if ($post_object instanceof \WP_Post_Type) {
                            $arg['title'] = sprintf(__('Post Archive: %s', 'wp-statistics'), $post_object->labels->name);
                            $arg['link']  = get_post_type_archive_link($post_type);
                        } else {
                            $arg['title'] = sprintf(__('Post Archive: %s', 'wp-statistics'), $slug);
                            $arg['link']  = home_url($slug);
                        }
                    } else {
                        $arg['title'] = __('Post Archive', 'wp-statistics');
                    }

                    break;
                default:
                    $arg = array(
                        'title'     => esc_html(get_the_title($page_id)),
                        'link'      => get_the_permalink($page_id),
                        'edit_link' => get_edit_post_link($page_id),
                        'meta'      => array(
                            'post_type' => get_post_type($page_id)
                        )
                    );

                    if ($page_id) {
                        $arg['report'] = Menus::admin_url('content-analytics', ['type' => 'single', 'post_id' => $page_id]);
                    }
                    break;
            }
        }

        return wp_parse_args($arg, $defaults);
    }

    /**
     * Get Top number of Hits Pages
     *
     * @param array $args
     * @return array|int|mixed
     */
    public static function getTop($args = array())
    {
        global $wpdb;

        // Define the array of defaults
        $defaults = array(
            'per_page' => 10,
            'paged'    => 1,
            'from'     => '',
            'to'       => '',
            'ago'      => '',
            'type'     => '',
        );

        $args = wp_parse_args($args, $defaults);

        // Check Default
        if (empty($args['from']) and empty($args['to'])) {
            if (array_key_exists($args['ago'], TimeZone::getDateFilters())) {
                $dateFilter   = TimeZone::calculateDateFilter($args['ago']);
                $args['from'] = $dateFilter['from'];
                $args['to']   = $dateFilter['to'];
            }
        }

        // Prepare Count Day
        if (!empty($args['from']) and !empty($args['to'])) {
            $count_day = TimeZone::getNumberDayBetween($args['from'], $args['to']);
        } else {
            if (is_numeric($args['ago']) and $args['ago'] > 0) {
                $count_day = $args['ago'];
            } else {
                $count_day = 30;
            }
        }

        // Get time ago Days Or Between Two Days
        if (!empty($args['from']) and !empty($args['to'])) {
            $days_list = TimeZone::getListDays(array('from' => $args['from'], 'to' => $args['to']));
        } else {
            if (is_numeric($args['ago']) and $args['ago'] > 0) {
                $days_list = TimeZone::getListDays(array('from' => TimeZone::getTimeAgo($args['ago'])));
            } else {
                $days_list = TimeZone::getListDays(array('from' => TimeZone::getTimeAgo($count_day)));
            }
        }

        // Get List Of Days
        $days_time_list = array_keys($days_list);

        // Date Time SQL
        $DateTimeSql = $wpdb->prepare("WHERE (`pages`.`date` BETWEEN %s AND %s)", reset($days_time_list), end($days_time_list));

        // Post Type SQL
        $postTypeSql = '';

        if (!empty($args['type'])) {
            if ($args['type'] == 'page') {
                $postTypeSql = $wpdb->prepare(" AND `pages`.`type` IN (%s, %s)", $args['type'], 'home');
            } else {
                $postTypeSql = $wpdb->prepare(" AND `pages`.`type` = %s", $args['type']);
            }
        }

        // Generate SQL
        $selectSql = "SELECT `pages`.`date`,`pages`.`uri`,`pages`.`id`,`pages`.`type`, SUM(`pages`.`count`) AS `count_sum` FROM `" . DB::table('pages') . "` `pages` {$DateTimeSql} {$postTypeSql}";

        // Group pages with ID of 0 by type and URI, and group the rest of pages by ID
        $sql = "
            ($selectSql AND `pages`.`id` != 0 GROUP BY `pages`.`id`)
            UNION
            ($selectSql AND `pages`.`id` = 0 GROUP BY `pages`.`uri`, `pages`.`type`)
            ORDER BY `count_sum` DESC
        ";

        // Get List Of Pages
        $list   = array();
        $result = $wpdb->get_results($sql . " LIMIT " . ($args['paged'] - 1) * $args['per_page'] . "," . $args['per_page']); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared

        foreach ($result as $item) {
            // Lookup the post title.
            $page_info = Pages::get_page_info($item->id, $item->type, $item->uri);

            $reportUrl = '';
            if (isset($page_info['meta']['term_taxonomy_id'])) {
                $reportUrl = Menus::admin_url('category-analytics', ['type' => 'single', 'term_id' => $page_info['meta']['term_taxonomy_id']]);
            } else if (isset($page_info['meta']['author_id'])) {
                $reportUrl = Menus::admin_url('author-analytics', ['type' => 'single-author', 'author_id' => $page_info['meta']['author_id']]);
            } else if (isset($page_info['meta']['post_type'])) {
                $reportUrl = Menus::admin_url('content-analytics', ['type' => 'single', 'post_id' => $item->id]);
            }

            // Push to list
            $list[] = array(
                'title'     => esc_html($page_info['title']),
                'link'      => $page_info['link'],
                'str_url'   => esc_url(urldecode($item->uri)),
                'hits_page' => $reportUrl,
                'number'    => number_format_i18n($item->count_sum)
            );
        }

        return $list;
    }

    /**
     * Count Number Page in DB Table
     *
     * @param string $group_by
     * @param array $args
     * @return mixed
     */
    public static function TotalCount($group_by = 'uri', $args = array())
    {
        global $wpdb;
        $where = [];

        // Date
        if (isset($args['from']) and isset($args['to']) and !empty($args['from']) and !empty($args['to'])) {
            $where[] = $wpdb->prepare("`date` BETWEEN %s AND %s", $args['from'], $args['to']);
        }

        if (!empty($args['type'])) {
            $where[] = $wpdb->prepare("`type` = %s", $args['type']);
        }

        $where = !empty($where) ? "WHERE " . implode(" AND ", $where) : "";

        // Return
        return $wpdb->get_var("SELECT COUNT(*) FROM (SELECT COUNT(*) FROM `" . DB::table('pages') . "` `pages` {$where} GROUP BY `{$group_by}`) AS totalCount"); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
    }

    /**
     * Get Post Type by ID
     *
     * @param $post_id
     * @return string
     */
    public static function get_post_type($post_id)
    {
        $post_type = get_post_type($post_id);
        return (in_array($post_type, array("post", "page", "product", "attachment")) ? $post_type : "post_type_" . $post_type);
    }

    /**
     * Convert Url to Page ID
     *
     * @param $uri
     * @return int
     */
    public static function uri_to_id($uri)
    {
        global $wpdb;
        $result = $wpdb->get_var(
            $wpdb->prepare("SELECT id FROM `" . DB::table('pages') . "` WHERE `uri` = %s and id > 0 ORDER BY date DESC", $uri)
        );
        if ($result == 0) {
            $result = 0;
        }

        return $result;
    }

    public static function checkIfPageIsHome($postID = false)
    {
        if (get_option('show_on_front') == 'page') {
            if (get_option('page_on_front') == $postID or get_option('page_for_posts') == $postID) {
                return true;
            }
        }
        return false;
    }

    /**
     * Get Page ID record in DB Table by Type and ID
     *
     * @param $type
     * @param $id
     * @return int
     */
    public static function getPageId($type, $id)
    {
        global $wpdb;
        $result = $wpdb->get_var(
            $wpdb->prepare("SELECT page_id FROM `" . DB::table('pages') . "` WHERE `type` = %s and `id` = %d ORDER BY date DESC", $type, $id)
        );
        if ($result == 0) {
            $result = 0;
        }

        return $result;
    }
}