<?php

namespace Prodigy\Includes\Frontend\Mappers;

use Prodigy\Includes\Content\Prodigy_Catalog_Filters_Parser;
use Prodigy\includes\helpers\Prodigy_Elementor;
use Prodigy\Includes\Helpers\Prodigy_Page;
use Prodigy\Includes\Helpers\Prodigy_Url_Helper;
use Prodigy\includes\models\Prodigy_Product_Attributes;
use Prodigy\Includes\Prodigy_Elementor_Template_Loader;
use Prodigy\Includes\Prodigy_Pagination;
use Prodigy\Includes\Support\Addons\Elementor\Widgets\Archive\Prodigy_Filters;
use Prodigy\Includes\Widgets\Prodigy_Filters_Widget;

/**
 * Prodigy filters data mapper
 *
 * @version    2.8.0
 * @package    Prodigy
 * @subpackage Prodigy/includes
 */
class Prodigy_Filter_Data_Mapper extends Prodigy_Main_Data_Mapper {

	/**
	 * Collected GET params
	 *
	 * @var array
	 */
	private array $get_request = array();

	/**
	 * Minimum quantity of items to show in filter
	 */
	const SHOW_ATTRIBUTE_VALUE_BY_COUNT_PRODUCTS = 1;
	const FILTER_BY_TITLE                        = 'Filter by';
	const ACTIVE_FILTER_TITLE                    = 'Active Filters';
	const PRICE_FILTER_TITLE                     = 'Price Filter';
	const DISPLAY_TYPE                           = 'accordion';

	const DEFAULT_WIDGET_ID = 'filter';


	/**
	 * @param array $options
	 *
	 * @return array
	 */
	public function get_default_parameters( array $options = array() ): array {
		if ( isset( $_GET['filter_widget_id'] ) ) {
			$filter_widget_id = sanitize_key( wp_unslash( $_GET['filter_widget_id'] ) );
			$options          = $this->get_elementor_widget_options( $filter_widget_id );
		}
		$query_string = $this->build_catalog_filter_query_string( $options );
		$data         = $this->prepare_filter_data( $query_string );
		$atts         = $this->prepare_widget_attributes( $options );

		$params = ( ! empty( $atts ) )
			? $this->prepare_params_with_attributes( $data, $atts )
			: $this->prepare_default_params();

		return $this->finalize_parameters( $params, $atts );
	}


	/**
	 * @param string $widget_id
	 *
	 * @return array
	 */
	public function get_elementor_widget_options( string $widget_id ): array {
		$options = array();
		if ( Prodigy_Elementor::is_elementor_enabled() ) {
			if (
				isset( $widget_id ) &&
				wp_doing_ajax() &&
				Prodigy_Elementor_Template_Loader::is_use_archive_template()
			) {
				$options = Prodigy_Elementor::get_widget_options( ( new Prodigy_Filters() )->get_name(), $widget_id );
			}
		}

		return $options;
	}

	/**
	 * @param array $filters
	 *
	 * @return array
	 */
	private function get_request_existing_attributes( array $filters ): array {
		$result = array();

		foreach ( $filters as $attribute ) {
			if ( ! empty( $this->get_request['attr']['attr'] ) && array_key_exists( $attribute['id'], $this->get_request['attr']['attr'] ) ) {
				$result[ $attribute['id'] ] = $this->get_request['attr']['attr'][ $attribute['id'] ];
			}
		}

		return $result;
	}


	/**
	 * @param array  $filters
	 * @param string $attribute
	 * @param string $attr_value
	 *
	 * @return string|string[]
	 */
	private function http_build_by_attr( array $filters, string $attribute, string $attr_value ) {
		$list['attr'] = $this->get_request_existing_attributes( $filters );

		if ( array_key_exists( $attribute, $list['attr'] ) ) {
			$attr_values                = explode( '%3B', $list['attr'][ $attribute ] );
			$attr_values[]              = $attr_value;
			$new_attr_values            = array_unique( $attr_values );
			$list['attr'][ $attribute ] = implode( '%3B', $new_attr_values );
		} else {
			$list['attr'][ $attribute ] = $attr_value;
		}
		if ( ( is_prodigy_product_taxonomy() || is_page( Prodigy_Page::prodigy_get_page_id( 'shop' ) ) ) && isset( $_SERVER['REQUEST_URI'] ) ) {
			$path_redirect = Prodigy_Url_Helper::prodigy_parse_request_uri();
		} else {
			$path_redirect = Prodigy_Url_Helper::prodigy_get_shop_url();
		}

		$path_redirect = remove_query_arg( array( 'search' ), $path_redirect );
		$path_redirect = remove_query_arg( array( 'pg' ), $path_redirect );
		$list_args     = add_query_arg( $list, $path_redirect );

		return str_replace( ';', '%3B', $list_args );
	}

	/**
	 * @param array $filters
	 *
	 * @return array
	 */
	private function get_output_attrs( array $filters ): array {
		$output_filter = array();

		if ( ! empty( $filters ) ) {
			foreach ( $filters as $filter ) {
				if ( isset( $filter['values'] ) ) {
					foreach ( $filter['values'] as $attribute_values ) {
						if ( $attribute_values['count'] < self::SHOW_ATTRIBUTE_VALUE_BY_COUNT_PRODUCTS ) {
							continue;
						}
						$output_filter[ $attribute_values['name'] ] = $this->http_build_by_attr( $filters, $filter['id'], $attribute_values['name'] );
					}
				}
			}
		}

		return $output_filter;
	}


	/**
	 * @param array $options
	 *
	 * @return string
	 */
	private function build_catalog_filter_query_string( array $options ): string {
		$params       = $this->clear_catalog_params( $_GET ?? array() );
		$query_params = $this->main_content->set_sort_products_query_parameter( $params, $options );

		$category = $this->main_content->get_catalog_category_param(
			$params['tax_slug'] ?? '',
			$params['tax_name'] ?? ''
		);

		if ( ! empty( $category ) ) {
			$query_params = $category . '&' . $query_params;
		}

		return $this->main_content->catalog_query_builder(
			$query_params,
			Prodigy_Pagination::get_per_page_by_options()
		);
	}

	/**
	 * @param string $query_string
	 *
	 * @return array
	 */
	private function prepare_filter_data( string $query_string ): array {
		$requestMaker   = $this->request_maker;
		$filters        = $requestMaker->do_catalog_filters_request( $query_string );
		$parsed_filters = Prodigy_Catalog_Filters_Parser::get_attributes( $filters );

		$query = '';
		if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'attributes-filter' ) ) {
			$query = $_GET ?? array();
		}
		if ( ! empty( $parsed_filters ) ) {
			return array(
				'filters' => $parsed_filters,
				'query'   => $query,
			);
		}

		return array();
	}

	/**
	 * @param array $attrs
	 *
	 * @return array
	 */
	private function prepare_widget_attributes( array $attrs ): array {
		$attrs = array_merge(
			array(
				'attribute_ids'   => array(),
				'attribute_names' => array(),
			),
			$attrs
		);

		if ( ! empty( $attrs['attribute_ids'] ) ) {
			$attrs['attribute_ids'] = $this->resolve_attribute_ids( $attrs['attribute_ids'] );
		}

		if ( ! empty( $attrs['attribute_names'] ) ) {
			$attrs['attribute_ids'] = $this->resolve_attribute_names( $attrs['attribute_names'] );
		}

		if ( empty( $attrs['attribute_ids'] ) && empty( $attrs['attribute_names'] ) ) {
			$list_attrs               = Prodigy_Product_Attributes::get_attribute_taxonomies();
			$attrs['attribute_ids']   = wp_list_pluck( $list_attrs, 'id' );
			$attrs['attribute_names'] = array();
		}

		return $attrs;
	}

	/**
	 * @param string $raw_ids
	 *
	 * @return array
	 */
	private function resolve_attribute_ids( string $raw_ids ): array {
		$ids          = array_filter( array_map( 'trim', explode( ',', $raw_ids ) ) );
		$resolved_ids = array();

		foreach ( $ids as $key => $attribute_id ) {
			$attribute = Prodigy_Product_Attributes::get_attribute_taxonomies_by_remote_id( (int) $attribute_id );
			if ( ! empty( $attribute ) ) {
				$resolved_ids[ $key ] = $attribute->id;
			}
		}

		return $resolved_ids;
	}

	/**
	 * @param string $raw_names
	 *
	 * @return array
	 */
	private function resolve_attribute_names( string $raw_names ): array {
		$names        = array_filter( array_map( 'trim', explode( ',', $raw_names ) ) );
		$resolved_ids = array();

		foreach ( $names as $key => $attribute_name ) {
			$attribute = Prodigy_Product_Attributes::get_info_prodigy_attr_taxonomy_by_slug( $attribute_name );
			if ( ! empty( $attribute ) ) {
				$resolved_ids[ $key ] = $attribute->id;
			}
		}

		return $resolved_ids;
	}

	private function prepare_params_with_attributes( array $data, array $atts ): array {
		$prepared_data = isset( $data['filters'] )
			? $this->apply_widget_settings( $data['filters'], $atts['attribute_ids'] )
			: array();

		$this->get_request['attr'] = $data['query'] ?? array();

		return array(
			'filters'        => $prepared_data,
			'active_filters' => true,
			'get_request'    => $this->get_request['attr'],
			'filters_output' => $this->get_output_attrs( $data['filters'] ?? array() ),
			'current_object' => get_queried_object(),
			'attr_shortcode' => $atts,
			'display'        => $atts['attrs_content_type'] ?? self::DISPLAY_TYPE,
		);
	}

	/**
	 * @return array
	 */
	private function prepare_default_params(): array {
		return array(
			'filters'        => array(),
			'current_object' => array(),
			'get_request'    => array(),
			'active_filters' => array(),
			'filters_output' => array(),
			'display'        => self::DISPLAY_TYPE,
		);
	}

	/**
	 * @param array $params
	 * @param array $atts
	 *
	 * @return array
	 */
	private function finalize_parameters( array $params, array $atts ): array {
		$params['elementor_filter_mode'] = isset( $atts['attrs_content_filter_button'] ) && $atts['attrs_content_filter_button'] === 'button';

		$params['filter_nonce']                = $this->filter_nonce;
		$params['attribute_ids']               = $atts['attribute_ids'] ?? '';
		$params['heading_text']                = $atts['heading_text'] ?? self::FILTER_BY_TITLE;
		$params['heading_active_text']         = $atts['heading_active_filter'] ?? self::ACTIVE_FILTER_TITLE;
		$params['count_show_attributes_value'] = $atts['count_show_attributes_value'] ?? Prodigy_Filters_Widget::DEFAULT_VISIBLE_AMOUNT;
		$params['vision_section_amount']       = $atts['vision_section_amount'] ?? Prodigy_Filters_Widget::DEFAULT_EXPANDED_AMOUNT;
		$params['idWidget']                    = $atts['idWidget'] ?? self::DEFAULT_WIDGET_ID;
		$params['attrs_content_prod_count']    = $atts['attrs_content_prod_count'] ?? 'yes';
		$params['layout']                      = ( $params['display'] === self::DISPLAY_TYPE )
			? 'shortcode/filter-accordion.php'
			: 'shortcode/filter-list.php';

		return $params;
	}

	/**
	 * @param array      $data
	 * @param array|null $list_attributes
	 *
	 * @return array
	 */
	private function apply_widget_settings( array $data, array $list_attributes = null ): array {
		$new_data          = array();
		$mapped_attributes = array();
		$attributes        = array();
		$settings          = array();

		if ( $list_attributes ) {
			$attributes = $list_attributes;
		} else {
			if ( isset( $_GET['filter_widget_id'] ) ) {
				$filter_widget_id = sanitize_key( wp_unslash( $_GET['filter_widget_id'] ) );
				$settings         = $this->get_elementor_widget_options( $filter_widget_id );
			}
			if ( ! empty( $settings ) ) {
				foreach ( $settings as $setting ) {
					if ( isset( $setting['list_attributes'] ) ) {
						$attributes = $setting['list_attributes'];
					}
				}
			}
		}

		if ( ! empty( $attributes ) ) {
			foreach ( $attributes as $attribute_id ) {
				$attribute_value                                  = Prodigy_Product_Attributes::get_attribute_taxonomies_by_id( $attribute_id );
				$mapped_attributes[ $attribute_value->remote_id ] = $attribute_id;
			}
		}

		if ( ! empty( $data ) ) {
			foreach ( $data as $key => $item ) {
				if ( isset( $mapped_attributes[ $item['id'] ] ) ) {
					$new_data[ $key ] = $item;
					$attribute        = Prodigy_Product_Attributes::get_attribute_taxonomies_by_remote_id( $item['id'] );
					if ( isset( $attribute ) ) {
						$new_data[ $key ]['slug'] = $attribute->slug;
					}
				}
			}
		}

		// Unset empty values.
		if ( ! empty( $new_data ) ) {
			foreach ( $new_data as $key => $attribute ) {
				if ( ! empty( $attribute['values'] ) ) {
					foreach ( $attribute['values'] as $key_val => $value ) {
						if ( empty( $value['count'] ) ) {
							unset( $new_data[ $key ]['values'][ $key_val ] );
						}
					}
				}
			}
		}

		return $new_data;
	}
}
