<?php
namespace ReyCore\WooCommerce;

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

use ReyCore\Plugin;
use ReyCore\Helper;

class Loop {

	protected $skins = [];

	protected $active_skin = '';

	private $components = [];
	private $component_groups = [];
	private $components_to_remove = [];
	private $product_item_classes = [];

	public static $custom_product_item_classes = [];
	public static $custom_product_item_inner_classes = [];

	public function __construct()
	{
		add_action( 'init', [$this, 'early_init'], 5 );
		add_action( 'init', [$this, 'init'] );
	}

	public function early_init(){
		$this->register_defaults();
		do_action('reycore/woocommerce/loop/init', $this);
	}

	public function register_defaults(){

		$defaults = [
			'skin' => [
				'LoopSkins/DefaultSkin',
				'LoopSkins/Basic',
				'LoopSkins/Wrapped',
			],
			'component' => [
				'LoopComponents/AddToCart',
				'LoopComponents/CatalogOrdering',
				'LoopComponents/Category',
				'LoopComponents/Excerpt',
				'LoopComponents/FeaturedBadge',
				'LoopComponents/FilterButton',
				'LoopComponents/FilterTopSidebar',
				'LoopComponents/NewBadge',
				'LoopComponents/Prices',
				'LoopComponents/Ratings',
				'LoopComponents/ResultCount',
				'LoopComponents/SoldOutBadge',
				'LoopComponents/ThumbnailsSecond',
				'LoopComponents/ThumbnailsSlideshow',
				'LoopComponents/Thumbnails',
				'LoopComponents/Title',
				'LoopComponents/Variations',
			],
		];

		foreach ( $defaults as $type => $items ) {
			foreach ($items as $item) {
				$class_name = Helper::fix_class_name($item, 'WooCommerce');
				call_user_func_array( [$this, "register_{$type}"], [ new $class_name() ]);
			}
		}

	}

	public function init(){

		add_action( 'woocommerce_product_query', [ $this, 'fix_pagination_current_query_original'], 1000);

		add_action( 'reycore/assets/register_scripts', [$this, 'register_scripts']);
		add_action( 'reycore/woocommerce/loop/scripts', [$this, 'enqueue_scripts']);

		add_filter( 'woocommerce_product_loop_start', [$this, 'product_loop_start']);
		add_filter( 'woocommerce_product_loop_end', [$this, 'product_loop_end']);

		add_action( 'reycore/woocommerce/loop/before_grid', [$this, 'before_grid']);
		add_action( 'reycore/woocommerce/loop/after_grid', [$this, 'after_grid']);

		add_action( 'woocommerce_no_products_found', [$this, 'no_products_global_section'], 5);

		// cleanups
		remove_action( 'woocommerce_before_shop_loop_item_title', 'woocommerce_show_product_loop_sale_flash', 10 );
		remove_action( 'woocommerce_before_shop_loop_item', 'woocommerce_template_loop_product_link_open', 10 );
		remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_product_link_close', 5 );

		// wrappers
		add_action( 'reycore/woocommerce/loop/before_grid', [$this, 'header_wrapper_start'], 14 );
		add_action( 'reycore/woocommerce/loop/before_grid', [$this, 'header_wrapper_end'], 41 );
		add_action( 'woocommerce_before_shop_loop_item', [$this, 'start_wrapper_div'], 0);
		add_action( 'woocommerce_after_shop_loop_item', 'reycore_wc__generic_wrapper_end', 999);
		add_action( 'woocommerce_before_subcategory', [$this, 'start_wrapper_div'], 0);
		add_action( 'woocommerce_after_subcategory', 'reycore_wc__generic_wrapper_end', 999);
		add_action( 'woocommerce_before_shop_loop_item_title', [$this, 'loop_product_link_open'], 9 );
		add_action( 'woocommerce_before_shop_loop_item_title', [$this, 'loop_product_link_close'], 12 );
		add_action( 'woocommerce_before_shop_loop_item_title', [$this, 'thumbnail_wrapper_start'], 5);
		add_action( 'woocommerce_before_shop_loop_item_title', [$this, 'thumbnail_wrapper_end'], 12);

		add_action( 'reycore/ajax/register_actions', [ $this, 'register_actions' ] );
		add_action( 'template_redirect', [ $this, 'late_components_init' ] );

		if( ! empty($this->components) ){
			foreach ($this->components as $key => $component) {
				$component->init();
			}
		}
	}

	public function get_active_skin(){
		return $this->active_skin ? $this->active_skin : get_theme_mod('loop_skin', 'basic');
	}

	public function register_skin( $class ){
		if( $skin_id = $class->get_id() ){
			$this->skins[ $skin_id ] = $class;
		}
	}

	public function get_skins_list( $skins = [] ){
		foreach ($this->skins as $id => $skin) {
			$skins[ $id ] = ($skin_name = $skin->get_list_option_key()) ? $skin_name : $skin->get_name();
		}
		return $skins;
	}

	public function get_skins( $skin_id = '' ){
		if( $skin_id && isset( $this->skins[ $skin_id ] ) ){
			return $this->skins[ $skin_id ];
		}
		return $this->skins;
	}

	public function register_scripts( $assets ){
		foreach ($this->skins as $skin) {
			$skin->register_scripts($assets);
		}
	}

	public function late_components_init(){
		foreach ($this->components as $key => $component) {
			$component->late_init();
		}
	}

	public function disable_pagination(){

		$non_paginated_loops = [
			'related',
			'up-sells',
			'cross-sells',
		];

		if( $q_name = wc_get_loop_prop( 'name' ) ){
			if( in_array($q_name, $non_paginated_loops, true) ){
				wc_set_loop_prop( 'is_paginated', false );
			}
		}

	}

	public function before_grid(){

		$this->active_skin = get_theme_mod('loop_skin', 'basic');

		$this->disable_pagination();

		$this->components_add_remove( 'add' );

		if( isset( $this->skins[ $this->active_skin ] ) && $skin = $this->skins[ $this->active_skin ] ){
			$skin->add_hooks();
		}

		add_filter( 'reycore/woocommerce/product_loop_attributes/v2', [ $this, 'skin_script_params'], 20 );

		$this->enqueue_scripts();
		$this->set_product_item_classes();
	}

	public function after_grid(){

		$this->components_add_remove( 'remove' );

		if( isset( $this->skins[ $this->active_skin ] ) && $skin = $this->skins[ $this->active_skin ] ){
			$skin->remove_hooks();
		}

		remove_filter( 'reycore/woocommerce/product_loop_attributes/v2', [ $this, 'skin_script_params'], 20 );

	}

	public function get_default_settings( $setting = '', $default = '' ){

		static $settings;

		if( is_null($settings) ){

			$settings = [
				'loop_alignment'            => 'left',
				'loop_add_to_cart_style'    => 'under',
				'loop_quickview'            => '1',
				'loop_quickview_style'      => 'under',
				'loop_quickview_position'   => 'bottom',
				'loop_quickview_icon_type'  => 'eye',
				'loop_wishlist_position'    => 'bottom',
				'wishlist_loop__icon_style' => 'minimal',
				'loop_discount_label'       => 'price',
			];

			if( isset( $this->skins[ $this->active_skin ] ) && $skin = $this->skins[ $this->active_skin ] ){
				$skin_settings = $skin->get_default_settings();
				$settings = wp_parse_args( $skin_settings, $settings );
			}

		}

		if( $setting ){
			return isset($settings[$setting]) ? $settings[$setting] : $default;
		}

		return $settings;
	}

	public function skin_script_params( $attributes ){

		$params = [];

		if( ($titles_height = reycore_wc__get_setting('product_titles_height', '')) && 'disabled' !== $titles_height ){

			$attributes['data-title-height'] = $titles_height;

			if( 'eq' === $titles_height ){
				$params['equalize_selectors'] = apply_filters('reycore/woocommerce/loop/equalize_selectors', [
					'.woocommerce-loop-product__title',
					// '.rey-productVariations',
				]);
			}
			else {
				if( ! get_theme_mod('product_titles_height_min', true) ){
					$attributes['data-title-height-min'] = '';
				}
			}
		}

		if( isset( $this->skins[ $this->active_skin ] ) && $skin = $this->skins[ $this->active_skin ] ){
			if( $script_params = $skin->get_script_params() ){
				$params = wp_parse_args($script_params, $params);
			}
		}

		$attributes['data-params'] = wp_json_encode($params);

		return $attributes;
	}



	public function register_component( $component_class ){

		if( $component_id = $component_class->get_id() ){

			$this->components[ $component_id ] = $component_class;

			// collect groups
			if( $component_group = $component_class->get_group() ){
				$this->component_groups[ $component_id ] = $component_group;
			}

		}
	}

	public function get_components(){
		return $this->components;
	}

	public function get_component( $component_id = '' ){

		if( $component_id && isset( $this->components[ $component_id ] ) ){
			return $this->components[ $component_id ];
		}

		return false;
	}

	public function get_components_groups(){
		return $this->component_groups;
	}

	public function components_add_remove( $task = 'add' ){

		// run cleanup
		if( 'remove' === $task && ! is_null($this->components_to_remove) ){

			foreach($this->components_to_remove as $component_to_remove){
				$this->hooks_add_remove($component_to_remove, $task);
			}

			return;
		}

		$skin_components = [];

		if( isset( $this->skins[ $this->active_skin ] ) && ($skin = $this->skins[ $this->active_skin ]) ){
			$skin_components = $skin->get_component_schemes();
		}

		$maybe_disable_grid_components = apply_filters('reycore/woocommerce/loop_components/disable_grid_components', false);

		do_action('reycore/woocommerce/loop_components/add', $this);

		foreach ($this->components as $id => $component) {

			// Disable Grid components
			if( $maybe_disable_grid_components && 'grid' === $component->loop_type() ){
				continue;
			}

			do_action('reycore/woocommerce/loop_components/add/component', $id, $component, $this);

			if( ! $component->get_status() ){
				continue;
			}

			if( isset($skin_components[$id]) ){
				$component->set_scheme( $skin_components[$id] );
			}

			do_action("reycore/woocommerce/loop_components:{$id}", $component, $this);

			$scheme = $component->get_scheme();

			if( empty($scheme) ){
				continue;
			}

			if( ! is_array($scheme) ){
				continue;
			}

			if( ! isset( $scheme['type'] ) ){
				continue;
			}

			if( ! isset($scheme['callback']) && method_exists( $component, 'render' ) ){
				$scheme['callback'] = [$component, 'render'];
			}

			if( $component_classes = $component->get_css_classes() ){
				$this->product_item_classes = $component_classes;
			}

			$this->hooks_add_remove( $scheme, $task );
		}
	}

	/**
	 * Add Remove Hook
	 *
	 * @since 1.0.0
	 **/
	private function hooks_add_remove($item, $task)
	{
		if( isset($item['type']) && isset($item['callback']) ){

			if( 'add' === $task ){
				$this->components_to_remove[] = $item;
			}

			call_user_func(
				sprintf('%s_%s', $task, $item['type'] ),
				$item['tag'],
				$item['callback'],
				isset($item['priority']) ? $item['priority'] : 10,
				isset($item['accepted_args']) ? $item['accepted_args'] : 1
			);
		}
	}

	function set_product_item_classes( $classes = [] ){

		if( ! empty($classes) ){
			return $this->product_item_classes = $classes;
		}

		$classes['rey_skin'] = 'rey-wc-skin--' . get_theme_mod('loop_skin', 'basic');
		$classes['text-align'] = 'rey-wc-loopAlign-' . reycore_wc__get_setting('loop_alignment');

		if(
			get_theme_mod('loop_animate_in', true) &&
			! reycore__elementor_edit_mode() &&
			wc_get_loop_prop( 'entry_animation' ) !== false
		){
			reycore_assets()->add_scripts('rey-animate-items');
			$classes['animated-entry'] = 'is-animated-entry';
		}

		// Check if product has custom height
		// @note: using get_option on WC's cropping option intentionally
		if( self::is_custom_image_height() ){
			$classes['image-container-height'] = ' --customImageContainerHeight';
		}

		// grid class
		if( get_option('woocommerce_thumbnail_cropping', '1:1') === 'uncropped' ){
			$classes[] = '--uncropped';
		}

		$this->product_item_classes = array_merge($this->product_item_classes, $classes, self::$custom_product_item_classes);
	}

	/**
	 * Utility
	 *
	 * Add animation hover class in loop
	 *
	 * @since 1.0.0
	 */
	function general_css_classes()
	{
		if ( ! self::is_product() ) {
			return;
		}

		return $this->product_item_classes;
	}

	function enqueue_scripts(){

		$assets = [
			'styles' => [
				'rey-wc-general',
				'rey-wc-general-deferred',
				'rey-wc-general-deferred-font',
				'rey-wc-loop',
			],
			'scripts' => [
				'reycore-wc-loop-grids',
			],
		];

		switch( get_theme_mod('loop_grid_layout', 'default') ):
			case"masonry":
				wp_enqueue_script('masonry');
				$assets['styles'][] = 'rey-wc-loop-grid-skin-masonry';
				break;
			case"masonry2":
				wp_enqueue_script('masonry');
				$assets['styles'][] = 'rey-wc-loop-grid-skin-masonry';
				$assets['styles'][] = 'rey-wc-loop-grid-skin-masonry2';
				break;
			case"metro":
				$assets['styles'][] = 'rey-wc-loop-grid-skin-metro';
				break;
			case"scattered":
				$assets['styles'][] = 'rey-wc-loop-grid-skin-scattered';
				break;
			case"scattered2":
				$assets['styles'][] = 'rey-wc-loop-grid-skin-scattered';
				break;
		endswitch;

		// List view
		if( self::is_mobile_list_view() ){
			$assets['styles'][] = 'rey-wc-loop-grid-mobile-list-view';
		}

		if( ($titles_height = reycore_wc__get_setting('product_titles_height')) && 'disabled' !== $titles_height ){
			if( 'eq' === $titles_height ){
				$assets['scripts'][] = 'reycore-wc-loop-equalize';
			}
			else {
				$assets['styles'][] = 'reycore-loop-titles-height';
			}
		}

		reycore_assets()->add_styles($assets['styles']);
		reycore_assets()->add_scripts($assets['scripts']);

		if( ($skin_id = $this->get_active_skin()) && isset( $this->skins[ $skin_id ] ) ){
			$this->skins[ $skin_id ]->add_scripts();
		}
	}

	/**
	 * Filter product list start to add custom CSS classes
	 *
	 * @since 1.1.2
	 */
	public function product_loop_start( $html )
	{
		$before_content = '';

		ob_start();

			do_action('reycore/woocommerce/loop/before_grid', $this);

			if( $q_name = wc_get_loop_prop( 'name' ) ){
				do_action('reycore/woocommerce/loop/before_grid/name=' . $q_name, $this);
			}

		if( $hooks_data = ob_get_clean() ){
			$before_content .= $hooks_data;
		}

		$search_for = 'class="products';

		if( self::is_mobile_list_view() ){
			$classes['mobile_listview'] = 'rey-wcGrid-mobile-listView';
		}

		$classes['skin'] = '--skin-' . esc_attr( $this->get_active_skin() );

		/**
		 * Grid Gap CSS class
		 */
		$classes['grid_gap'] = reycore_wc__get_gap_css_class();

		/**
		 * Product Grid CSS class
		 */

		$grid_layout = get_theme_mod('loop_grid_layout', 'default');
		$classes['grid_layout'] = 'rey-wcGrid-' . esc_attr( $grid_layout );

		if( 'metro' === $grid_layout ){
			$classes['metro_prevents'] = '--prevent-colspan';
		}

		if( wc_get_loop_prop( 'is_paginated' ) && wc_get_loop_prop( 'total_pages' ) ){

			$classes['paginated'] = '--paginated';

			if( in_array(get_theme_mod('loop_pagination', 'paged'), ['load-more', 'infinite'], true) ){
				$classes['paginated_infinite'] = '--infinite';
			}
		}

		$attributes['data-cols'] = wc_get_loop_prop( 'columns' );
		$attributes['data-cols-tablet'] = reycore_wc_get_columns('tablet');
		$attributes['data-cols-mobile'] = reycore_wc_get_columns('mobile');
		$attributes['data-skin'] = esc_attr( $this->get_active_skin() );

		$html = str_replace( $search_for, $search_for . ' ' . reycore__product_grid_classes($classes), $html );
		$html = str_replace( '">', sprintf('" %s>', reycore__product_grid_attributes($attributes) ), $html );

		return $before_content . $html;
	}

	public function product_loop_end( $html )
	{

		$after_content = '';

		ob_start();

			do_action('reycore/woocommerce/loop/after_grid', $this);

			if( $q_name = wc_get_loop_prop( 'name' ) ){
				do_action('reycore/woocommerce/loop/after_grid/name=' . $q_name, $this);
			}

		if( $hooks_data = ob_get_clean() ){
			$after_content .= $hooks_data;
		}

		global $wp_query;

		if( $colspans = $wp_query->get('colspans') ){
			$after_content .= sprintf('<div data-colspans="%d"></div>', $colspans);
		}

		return $html . $after_content;
	}

	public function no_products_global_section(){

		if( ! class_exists('\ReyCore\Elementor\GlobalSections') ){
			return;
		}

		if( ! ($gs = get_theme_mod('loop_empty__gs', '')) ){
			return;
		}

		if( ! ($mode = get_theme_mod('loop_empty__mode', 'overwrite')) ){
			return;
		}

		if( 'overwrite' === $mode ){
			remove_action( 'woocommerce_no_products_found', 'wc_no_products_found', 10 );
			echo \ReyCore\Elementor\GlobalSections::do_section($gs, false, true);
			return;
		}

		$pos[$mode] = \ReyCore\Elementor\GlobalSections::do_section($gs, false, true);

		if( isset($pos['before']) && ($before = $pos['before']) ){
			add_action( 'woocommerce_no_products_found', function() use ($before) {
				echo $before;
			}, 9 );
		}

		if( isset($pos['after']) && ($after = $pos['after']) ){
			add_action( 'woocommerce_no_products_found', function() use ($after) {
				echo $after;
			}, 11 );
		}

	}


	/**
	 * Wrap loop header
	 *
	 * @since 1.0.0
	 **/
	public function header_wrapper_start()
	{

		if ( ! wc_get_loop_prop( 'is_paginated' ) ) {
			return;
		}

		$classes = [];

		if( reycore_wc__check_filter_btn() ){
			$classes['has_btn'] = '--has-filter-btn';
		}

		do_action('reycore/loop_products/before_header_start');

		echo sprintf('<div class="rey-loopHeader %s">', esc_attr( implode(' ', apply_filters('rey/woocommerce/loop/header_classes', $classes ) ) ) );

		reycore_assets()->add_styles('rey-wc-loop-header');

		do_action('reycore/loop_products/after_header_start');

	}

	/**
	 * Wrap loop header
	 *
	 * @since 1.0.0
	 **/
	public function header_wrapper_end()
	{
		if ( ! wc_get_loop_prop( 'is_paginated' ) ) {
			return;
		}

		do_action('reycore/loop_products/before_header_end');

		echo '</div>';

		do_action('reycore/loop_products/after_header_end');

	}


	/**
	 * Wrap layout - start
	 *
	 * @since 1.0.0
	 **/
	function start_wrapper_div()
	{

		if( get_theme_mod('loop_edit_link', true) && function_exists('rey__edit_link') ){
			rey__edit_link(['class' => 'rey-productEditLink']);
		}

		printf('<div class="rey-productInner %s">', esc_attr(implode(' ', self::$custom_product_item_inner_classes)));
	}

	/**
	 * Utility
	 *
	 * Checks if the thumbnail should be wrapped with link
	 *
	 * @since 1.2.0
	 */
	public function wrap_thumbnails_with_link() {
		return apply_filters('reycore/woocommerce/loop/wrap_thumbnails_with_link', true);
	}

	public function loop_product_link_open(){
		if( $this->wrap_thumbnails_with_link() ){
			woocommerce_template_loop_product_link_open();
		}
	}

	public function loop_product_link_close(){
		if( $this->wrap_thumbnails_with_link() ){
			woocommerce_template_loop_product_link_close();
		}
	}

	public function thumbnail_wrapper_start()
	{
		echo '<div class="rey-productThumbnail">';
	}

	public function thumbnail_wrapper_end()
	{

		foreach([ 'top-left', 'top-right', 'bottom-left', 'bottom-right', 'bottom-center' ] as $position){

			ob_start();
			do_action('reycore/loop_inside_thumbnail/' . $position);
			$th_content = ob_get_clean();

			if( !empty($th_content) ){

				if( in_array($position, ['bottom-left', 'bottom-right', 'bottom-center'], true) ){
					$position .= ' rey-thPos--bottom';
				}

				printf('<div class="rey-thPos rey-thPos--%2$s" data-position="%2$s">%1$s</div>', $th_content, $position);
			}
		}

		echo '</div>';

	}

	public static function is_mobile_list_view(){
		return reycore_wc_get_columns('mobile') === 1 && get_theme_mod('woocommerce_catalog_mobile_listview', false);
	}

	public static function is_product(){
		return in_array( get_post_type(), [ 'product', 'product_variation' ], true );
	}

	public static function is_custom_image_height(){
		return ! in_array( get_theme_mod('loop_grid_layout', 'default'), [ 'metro' ]) &&
		get_option('woocommerce_thumbnail_cropping', '1:1') === 'uncropped' &&
		get_theme_mod('custom_image_height', false) === true ;
	}

	public function register_actions( $ajax_manager ) {
		$ajax_manager->register_ajax_action( 'get_loop_skins_list', [$this, 'customizer__get_loop_skins'], 1 );
	}

	public function customizer__get_loop_skins(){
		return $this->get_skins_list();
	}

	public function fix_pagination_current_query_original( $query ){

		if( ! empty( $_REQUEST['product-page'] ) && ($page = absint($_REQUEST['product-page']))  ){
			if ( 1 < $page && ! $query->get('paged') ) {
				$query->set('paged', $page);
			}
		}

	}
}
