<?php

if (!defined('ABSPATH')) {
    exit; // Exit if accessed directly
}

class WOOF_URL_PARSER {

    private $current_request = array();
    private $filter_prefix = '';
    public $special_filters = [];

    public function __construct() {

        $this->init();
    }

    public function get_filter_prefix() {
        if (empty($this->filter_prefix)) {

            $this->filter_prefix = woof()->get_swoof_search_slug();
        }

        return $this->filter_prefix;
    }

    public function init() {



        $this->special_filters = array(
            'instock' => array('stock' => 'instock'),
            'onsale' => array('onsales' => 'salesonly'),
            'featured' => array('product_visibility' => 'featured'),
            'backorder_not_in' => array('backorder' => 'onbackorder'),
        );

        if (!is_admin()) {
            add_filter('do_parse_request', array($this, 'url_process'), 10, 3);
        }
        add_filter('woof_get_request_data', array($this, 'add_request'), 10);
        add_filter('woof_draw_products_get_args', array($this, 'ajax_draw_products'), 10, 2);
    }

    public function url_process($do, $WP, $extra_query_vars) {

        if (!$this->get_url_request()) {
            return $do;
        }

        global $wp_rewrite;
        $post_data = $this->get_post();
        $get_data = $this->get_get();

        $self = '';
        if (isset($_SERVER['PHP_SELF'])) {
            $self = WOOF_HELPER::get_server_var('PHP_SELF');
        }

        $WP->query_vars = [];
        $post_type_query_vars = [];

        if (is_array($extra_query_vars)) {
            $WP->extra_query_vars = & $extra_query_vars;
        } elseif (!empty($extra_query_vars)) {
            $WP->extra_query_vars = WOOF_HELPER::safe_parse_str($extra_query_vars);
        }
        //Source wp-includes/class-wp.php
        $rewrite_rules = $wp_rewrite->wp_rewrite_rules();

        if (!empty($rewrite_rules)) {
            $path_info = '';
            if (isset($_SERVER['PATH_INFO'])) {
                $path_info = WOOF_HELPER::get_server_var('PATH_INFO');
            }
            $error = '404';
            $WP->did_permalink = true;

            list( $path_info ) = explode('?', $path_info);
            $path_info = str_replace('%', '%25', $path_info);

            $cleared_url = $this->get_cleared_url($this->get_request_uri());

            list( $req_uri ) = explode('?', $cleared_url);
            $req_uri = str_replace($path_info, '', $req_uri);

            $req_uri = $this->check_url($req_uri);
            $path_info = $this->check_url($path_info);
            $self = $this->check_url($self);

            if (!empty($path_info) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $path_info)) {
                $initial_path = $path_info;
            } else {

                if ($req_uri == $wp_rewrite->index) {
                    $req_uri = '';
                }
                $initial_path = $req_uri;
            }
            $requested_file = $req_uri;

            $WP->request = $initial_path;
            // Look for matches.
            $request_match = $initial_path;

            if (empty($request_match)) {

                if (isset($rewrite_rules['$'])) {
                    $WP->matched_rule = '$';
                    $query_var = $rewrite_rules['$'];
                    $matches = array('');
                } else {
                    $query_var = '';
                    $matches = array('');
                }
            } else {

                foreach ((array) $rewrite_rules as $match => $query_var) {
                    // If the requesting file is the anchor of the match, prepend it
                    // to the path info.
                    if (!empty($requested_file) && strpos($match, $requested_file) === 0 && $requested_file != $initial_path) {
                        $request_match = $requested_file . '/' . $initial_path;
                    }

                    if (preg_match("#^$match#", $request_match, $matches) ||
                            preg_match("#^$match#", urldecode($request_match), $matches)) {

                        if ($wp_rewrite->use_verbose_page_rules && preg_match('/pagename=\$matches\[([0-9]+)\]/', $query_var, $varmatch)) {
                            // This is a verbose page match, let's check to be sure about it.
                            $page = get_page_by_path($matches[$varmatch[1]]);
                            if (!$page) {
                                continue;
                            }

                            $post_status_obj = get_post_status_object($page->post_status);
                            if (!$post_status_obj->public && !$post_status_obj->protected && !$post_status_obj->private && $post_status_obj->exclude_from_search) {
                                continue;
                            }
                        }
                        $WP->matched_rule = $match;
                        break;
                    }
                }
            }

            if (isset($WP->matched_rule)) {

                // Got a match.
                // Trim the query of everything up to the '?'.				
                $query_var = preg_replace('!^.+\?!', '', $query_var);

                $query_var = addslashes(\WP_MatchesMapRegex::apply($query_var, $matches));

                $WP->matched_query = $query_var;
                // Filter out non-public query vars
                $perma_query_vars = WOOF_HELPER::safe_parse_str($query_var);
                // If we're processing a 404 request, clear the error var since we found something.
                if ('404' == $error) {
                    unset($error, $get_data['error']);
                }
            }
            // If req_uri is empty or if it is a request for ourself, unset error.
            if (empty($initial_path) || $requested_file == $self || strpos($self, 'wp-admin/') !== false) {
                unset($error, $get_data['error']);

                if (isset($perma_query_vars) && strpos($self, 'wp-admin/') !== false && (!isset($post_data['link']))) {
                    unset($perma_query_vars);
                }

                $WP->did_permalink = false;
            }
        }



        $WP->public_query_vars = apply_filters('query_vars', $WP->public_query_vars);

        foreach (get_post_types([], 'objects') as $post_type => $t) {
            if (is_post_type_viewable($t) && $t->query_var) {
                $post_type_query_vars[$t->query_var] = $post_type;
            }
        }

        foreach ($WP->public_query_vars as $wpvar) {
            if (isset($WP->extra_query_vars[$wpvar])) {
                $WP->query_vars[$wpvar] = $WP->extra_query_vars[$wpvar];
            } elseif (isset($get_data[$wpvar]) && isset($post_data[$wpvar]) && $get_data[$wpvar] !== $post_data[$wpvar]) {
                wp_die(esc_html__('Forbidden', 'woocommerce-products-filter'), 400);
            } elseif (isset($post_data[$wpvar])) {
                $WP->query_vars[$wpvar] = $post_data[$wpvar];
            } elseif (isset($get_data[$wpvar])) {
                $WP->query_vars[$wpvar] = $get_data[$wpvar];
            } elseif (isset($perma_query_vars[$wpvar])) {
                $WP->query_vars[$wpvar] = $perma_query_vars[$wpvar];
            }

            if (!empty($WP->query_vars[$wpvar])) {
                if (!is_array($WP->query_vars[$wpvar])) {
                    $WP->query_vars[$wpvar] = (string) $WP->query_vars[$wpvar];
                } else {
                    foreach ($WP->query_vars[$wpvar] as $vkey => $v) {
                        if (is_scalar($v)) {
                            $WP->query_vars[$wpvar][$vkey] = (string) $v;
                        }
                    }
                }

                if (isset($post_type_query_vars[$wpvar])) {
                    $WP->query_vars['post_type'] = $post_type_query_vars[$wpvar];
                    $WP->query_vars['name'] = $WP->query_vars[$wpvar];
                }
            }
        }
        // Convert urldecoded spaces back into '+'.
        foreach (get_taxonomies(['object_type' => 'product'], 'objects') as $taxonomy => $t) {

            if ($t->query_var && isset($WP->query_vars[$t->query_var])) {
                $WP->query_vars[$t->query_var] = str_replace(' ', '+', $WP->query_vars[$t->query_var]);
            }
        }
        // Don't allow non-publicly queryable taxonomies to be queried from the front end.
        if (!is_admin()) {
            foreach (get_taxonomies(array('object_type' => 'product', 'publicly_queryable' => false), 'objects') as $taxonomy => $t) {

                if (isset($WP->query_vars['taxonomy']) && $taxonomy === $WP->query_vars['taxonomy']) {
                    unset($WP->query_vars['taxonomy'], $WP->query_vars['term']);
                }
            }
        }
        // Limit publicly queried post_types to those that are 'publicly_queryable'.
        if (isset($WP->query_vars['post_type'])) {
            $queryable_post_types = get_post_types(array('publicly_queryable' => true));
            if (!is_array($WP->query_vars['post_type'])) {
                if (!in_array($WP->query_vars['post_type'], $queryable_post_types)) {
                    unset($WP->query_vars['post_type']);
                }
            } else {
                $WP->query_vars['post_type'] = array_intersect($WP->query_vars['post_type'], $queryable_post_types);
            }
        }

        $WP->query_vars = wp_resolve_numeric_slug_conflicts($WP->query_vars);

        foreach ((array) $WP->private_query_vars as $var) {
            if (isset($WP->extra_query_vars[$var])) {
                $WP->query_vars[$var] = $WP->extra_query_vars[$var];
            }
        }

        if (isset($error)) {
            $WP->query_vars['error'] = $error;
        }


        $WP->query_vars = apply_filters('request', $WP->query_vars);

        global $wp_version;

        if (version_compare($wp_version, '6.0') >= 0) {
            $WP->query_posts();
            $WP->handle_404();
            $WP->register_globals();
        } else {
            do_action_ref_array('parse_request', array(&$WP));
        }


        return false;
    }

    public function get_cleared_url($url) {
        $request_url = $this->get_url_request($url);

        $url = str_replace($request_url, '/', $url);
        return $url;
    }

    public function get_url_request($url = null) {
        if (!$url) {
            $url = $this->get_request_uri();
        }

        if (!$this->current_request) {
            $this->current_request = $this->get_search_request($url);
        }
        return $this->current_request;
    }

    public function check_url($url) {
        $home = trim(parse_url(home_url(), PHP_URL_PATH), '/');
        $home_regex = sprintf('|^%s|i', preg_quote($home, '|'));

        $url = trim($url, '/');
        $url = preg_replace($home_regex, '', $url);
        $url = trim($url, '/');
        return $url;
    }

    public function get_search_request($url) {

        $cleared_url = $url;
        $clear_array = array('/page/', '?', '#');
        $request_url = "";
        foreach ($clear_array as $sign) {
            $tmp_url = explode($sign, $cleared_url, 2);
            $cleared_url = $tmp_url[0];
        }
        $filter_data = array();

        if ('/' != substr($cleared_url, -1)) {
            $cleared_url = $cleared_url . '/';
        }


        $pos = stripos($cleared_url, '/' . $this->get_filter_prefix() . '/');

        if (false !== $pos) {
            $request_url = substr($cleared_url, $pos);
        }


        return $request_url;
    }

    public function create_request($request) {
        $url = $this->get_url_request();
        if ($url) {
            $request = $request + $this->parse_url_query($url);
        }
        return $request;
    }

    public function get_all_items() {

        $settings = woof()->settings;
        $items_order = array();
        $all_items = array();
        $taxonomies = woof()->get_taxonomies();
        $taxonomies_keys = array_keys($taxonomies);
        if (isset($settings['items_order']) AND!empty($settings['items_order'])) {
            $items_order = explode(',', $settings['items_order']);
        } else {
            $items_order = array_merge(woof()->items_keys, $taxonomies_keys);
        }
        foreach (array_merge(woof()->items_keys, $taxonomies_keys) as $key) {
            if (!in_array($key, $items_order)) {
                $items_order[] = $key;
            }
        }

        $items_order = array_merge($items_order, array_keys($this->special_filters));
        $tax_relations = apply_filters('woof_main_query_tax_relations', array());

        foreach ($items_order as $f_key) {
            $f_real_keys = $f_key;
            if (isset($tax_relations[$f_real_keys]) AND $tax_relations[$f_real_keys] == 'NOT IN') {
                $f_real_keys = 'rev_' . $f_real_keys;
            }
            $f_key = preg_replace('/^pa_/', '', $f_key);

            switch ($f_key) {
                case 'by_price':
                    $f_key = 'price';
                    break;
                case 'by_rating':
                    unset($all_items[$f_key]);
                    $all_items['min_rating'] = 'min_rating';
                    break;
                case 'by_author':
                    unset($all_items[$f_key]);
                    $all_items['author'] = 'woof_author';
                    break;
                case 'by_sku':
                    unset($all_items[$f_key]);
                    $all_items['sku'] = 'woof_sku';
                    break;
                case 'by_text':
                case 'by_text_2':
                    unset($all_items[$f_key]);
                    $all_items['name'] = 'woof_text';
                    break;
            }
            if ($f_key == 'by_price') {
                $f_key = 'price';
            } elseif ($f_key == 'by_rating') {
                unset($all_items[$f_key]);
                $all_items['min_rating'] = 'min_rating';
            } elseif ($f_key == 'by_author') {
                unset($all_items[$f_key]);
                $all_items['author'] = 'woof_author';
            }
            $all_items[$f_key] = $f_real_keys; //to  do
        }

        return $all_items;
    }

    public function parse_url_query($url_query) {

        $filter_data = array();
        $all_filter_data = array();
        $request_array = explode('/', trim($url_query, '/'));

        if ($request_array[0] !== $this->get_filter_prefix()) {
            return $filter_data;
        }

        $filter_data[$this->get_filter_prefix()] = 1;

        $settings = woof()->settings;
        $taxonomies = woof()->get_taxonomies();
        $taxonomies_keys = array_keys($taxonomies);
        $all_items = $this->get_all_items();

        foreach ($request_array as $string) {

            foreach ($all_items as $f_key => $f_real_key) {

                $s_match = preg_replace('/^' . $f_key . '(-|$)/', '', $string);

                if ($s_match != $string) {


                    if (isset($taxonomies_keys[$f_real_key])) {
                        $separator = '-or-';
                        if (isset($settings['comparison_logic'][$f_real_key]) AND 'AND' == $settings['comparison_logic'][$f_real_key]) {
                            $separator = '-and-';
                        }
                        $separator = '-and-';
                        $terms_slug = explode($separator, $s_match);
                        $filter_data[$f_real_key] = implode(',', $terms_slug);
                    } elseif ($f_key == $string AND isset($this->special_filters[$f_key])) {

                        $filter_data = array_merge($filter_data, $this->special_filters[$f_key]);
                    } elseif ('price' == $f_key) {

                        $prices = explode('-to-', $s_match);

                        if (isset($prices[1])) {
                            $filter_data['min_price'] = $prices[0];
                            $filter_data['max_price'] = $prices[1];
                        }
                    } else {

                        $needle = array('-and-', '-or-', '-to-', '+');
                        $replase = array(',', ',', '^', ' ');
                        $s_match = urldecode($s_match);
                        if (isset($settings['meta_filter']) AND isset($settings['meta_filter'][$f_real_key])) {
                            $f_real_key = $settings['meta_filter'][$f_real_key]['search_view'] . '_' . $f_real_key;
                        }
                        $filter_data[$f_real_key] = str_replace($needle, $replase, $s_match);
                    }
                }
            }
        }

        return $filter_data;
    }

    public function get_request_uri() {
        $uri = false;
        if (isset($_SERVER['REQUEST_URI'])) {
            $uri = WOOF_HELPER::get_server_var('REQUEST_URI');
        }

        return apply_filters('woof_override_seo_request_uri', $uri);
    }

    public function get_post() {
        return WOOF_HELPER::sanitize_array($_POST);
    }

    public function get_get() {
        return WOOF_HELPER::sanitize_array($_GET);
    }

    public function add_request($data) {


        if (!is_array($data)) {
            $data = array();
        }
        $url = $this->get_url_request();
        $request = array();
        if ($url) {
            $request = $this->parse_url_query($url);
        }
        $data = array_merge($data, $request);

        if (isset($data['min_price'])) {
            $_GET['min_price'] = floatval($data['min_price']);
        }
        if (isset($data['max_price'])) {
            $_GET['max_price'] = floatval($data['max_price']);
        }

        return $data;
    }

    public function ajax_draw_products($get, $link) {
        $url = $this->get_url_request($link);
        $request = array();
        if ($url) {
            $request = $this->parse_url_query($url);
            $request[$this->get_filter_prefix()] = 1;
        }
        $get = array_merge($get, $request);
        $get[$this->get_filter_prefix()] = 1;
        return $get;
    }

}
