<?php
/**
 * Shoptimizer Load More
 *
 * @package  Shoptimizer
 * @author   CommerceGurus
 * @since    1.0.0
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! class_exists( 'Shoptimizer_Load_More' ) ) :

class Shoptimizer_Load_More {

	/**
	 * Constructor
	 */
	public function __construct() {
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ) );
		add_action( 'wp_ajax_shoptimizer_load_more', array( $this, 'ajax_load_more' ) );
		add_action( 'wp_ajax_nopriv_shoptimizer_load_more', array( $this, 'ajax_load_more' ) );

		add_action( 'woocommerce_after_shop_loop', array( $this, 'render_load_more_ui' ), 35 );
		add_filter( 'body_class', array( $this, 'body_class' ), 40, 1 );

		add_action( 'woocommerce_before_shop_loop', array( $this, 'set_pre_posts' ), 99 );
	}

	/**
	 * Enqueue frontend assets
	 */
	public function enqueue_assets() {

		if ( ! is_shop() && ! is_product_category() && ! is_product_tag() ) {
			return;
		}

		// Check if load more feature is enabled in customizer
		if ( ! get_theme_mod( 'shoptimizer_layout_woocommerce_load_more', false ) ) {
			return;
		}

		$theme   = wp_get_theme();
		$version = $theme->get( 'Version' );

		wp_enqueue_script(
			'shoptimizer-load-more',
			get_template_directory_uri() . '/assets/js/load-more.min.js',
			array(),
			$version,
			true
		);

		$first_page   = isset( $_GET['fpage'] ) ? absint( $_GET['fpage'] ) : 0;
		$current_page = max( 1, get_query_var( 'paged' ) );
		$max_pages    = absint( $GLOBALS['wp_query']->max_num_pages );
		if ( $first_page < 1 || $first_page >= $current_page || $first_page >= $max_pages  ) {
			$first_page = $current_page;
		}
		$load_more_text = get_theme_mod( 'shoptimizer_layout_woocommerce_load_more_text', __( 'Load more products', 'shoptimizer' ) );

		wp_localize_script(
			'shoptimizer-load-more',
			'ShoptimizerLoadMore',
			array(
				'ajax_url'       => admin_url( 'admin-ajax.php' ),
				'nonce'          => wp_create_nonce( 'shoptimizer_load_more_nonce' ),
				'query_vars'     => wp_json_encode( $GLOBALS['wp_query']->query ),
				'max_pages'      => $max_pages,
				'current_page'   => $current_page,
				'orderby'        => isset( $_GET['orderby'] ) && ! empty( $_GET['orderby'] ) ? sanitize_text_field( wp_unslash( $_GET['orderby'] ) ) : 'menu_order', // phpcs:ignore
				'result_text'    => sprintf( esc_html__( 'Showing {FROM}-{TO} of %d results', 'shoptimizer' ), absint( $GLOBALS['wp_query']->found_posts ) ),
				'result_total'   => absint( $GLOBALS['wp_query']->found_posts ),
				'result_limit'   => absint( apply_filters( 'loop_shop_per_page', wc_get_default_products_per_row() * wc_get_default_product_rows_per_page() ) ),
				'first_page'     => $first_page,
				'load_more_text' => esc_html( $load_more_text ),
				'i18n'           => array(
					'error_message' => esc_html__( 'Failed to load more products. Please try again.', 'shoptimizer' ),
				),
			)
		);
	}

	/**
	 * Render Load More UI
	 */
	public function render_load_more_ui() {
		global $wp_query;

		if ( $wp_query->max_num_pages <= 1 ) {
			return;
		}

		$paged = max( 1, get_query_var( 'paged' ), get_query_var( 'page' ) );
		if ( $wp_query->max_num_pages === $paged ) {
			return;
		}

		$total         = absint( $wp_query->found_posts );
		$per_page      = absint( $wp_query->get( 'posts_per_page' ) );
		$viewed        = min( $per_page, $total );
		$load_more_text = get_theme_mod( 'shoptimizer_layout_woocommerce_load_more_text', __( 'Load more products', 'shoptimizer' ) );
		?>

		<div class="shoptimizer-load-more-wrapper">
			<p class="load-more-status" aria-live="polite">
				<?php
				printf(
					/* translators: 1: viewed count, 2: total products */
					esc_html__( 'You\'ve viewed %1$s of %2$s products', 'shoptimizer' ),
					'<span class="viewed-count">' . esc_html( $viewed ) . '</span>',
					esc_html( $total )
				);
				?>
			</p>
			<div class="load-more-progress" role="progressbar" aria-label="<?php esc_attr_e( 'Products viewed progress', 'shoptimizer' ); ?>" aria-valuemin="0" aria-valuemax="<?php echo esc_html( $total ); ?>" aria-valuenow="<?php echo esc_html( $viewed ); ?>">
				<div class="load-more-progress-bar"></div>
			</div>
			<button id="shoptimizer-load-more-btn" class="button" type="button" aria-label="<?php echo esc_attr( $load_more_text ); ?>">
				<?php echo esc_html( $load_more_text ); ?>
			</button>
			<div class="load-more-spinner" style="display: none;">
				<svg width="32" height="32" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_5nOS{transform-origin:center;animation:spinner_sEAn .75s infinite linear}@keyframes spinner_sEAn{100%{transform:rotate(360deg)}}</style><path d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z" opacity=".25"/><path d="M10.72,19.9a8,8,0,0,1-6.5-9.79A7.77,7.77,0,0,1,10.4,4.16a8,8,0,0,1,9.49,6.52A1.54,1.54,0,0,0,21.38,12h.13a1.37,1.37,0,0,0,1.38-1.54,11,11,0,1,0-12.7,12.39A1.54,1.54,0,0,0,12,21.34h0A1.47,1.47,0,0,0,10.72,19.9Z" class="spinner_5nOS"/></svg></div>
			</div>
		<?php
	}

	/**
	 * Body class
	 */
	public function body_class( $classes ) {

		if ( ! is_shop() && ! is_product_category() && ! is_product_tag() ) {
			return $classes;
		}

		$classes[] = 'shoptimizer-load-more';

		return $classes;
	}

	/**
	 * AJAX handler
	 */
	public function ajax_load_more( $args = array() ) {
		global $shoptimizer_load_previous;

		// Verify nonce for security (only for actual AJAX requests, not internal calls)
		if ( ! isset( $shoptimizer_load_previous ) || ! $shoptimizer_load_previous ) {
			check_ajax_referer( 'shoptimizer_load_more_nonce', 'nonce' );
		}

		$paged = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
		$paged = isset( $args['page'] ) ? absint( $args['page'] ) : $paged;

		$query_vars = array();

		if ( isset( $_POST['query'] ) ) {
			$query_vars = json_decode( wp_unslash( $_POST['query'] ), true );
		} elseif ( isset( $args['query'] ) ) {
			$query_vars = json_decode( wp_unslash( $args['query'] ), true );
		}

		if ( ! is_array( $query_vars ) ) {
			if ( isset( $shoptimizer_load_previous ) && true === $shoptimizer_load_previous ) {
				return;
			} else {
				wp_die();
			}
		}

		if ( isset( $_POST['orderby'] ) && ! empty( $_POST['orderby'] ) ) {
			$_GET['orderby'] = sanitize_text_field( wp_unslash( $_POST['orderby'] ) );
		}
		if ( isset( $query_vars['post_type'] ) && ! empty( $query_vars['post_type'] ) ) {
			$_GET['post_type'] = sanitize_text_field( wp_unslash( $query_vars['post_type'] ) );
		}

		$ordering_args         = WC()->query->get_catalog_ordering_args();
		$query_vars['orderby'] = $ordering_args['orderby'];
		$query_vars['order']   = $ordering_args['order'];
		if ( $ordering_args['meta_key'] ) {
			$query_vars['meta_key'] = $ordering_args['meta_key']; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
		}
		$query_vars['meta_query'] = WC()->query->get_meta_query(); // phpcs:ignore
		$query_vars['tax_query']  = WC()->query->get_tax_query( array(), true ); // phpcs:ignore

		$query_vars['paged'] = $paged;

		$query_vars['posts_per_page'] = absint( apply_filters( 'loop_shop_per_page', wc_get_default_products_per_row() * wc_get_default_product_rows_per_page() ) );		
		$query_vars['posts_per_page'] = isset( $_POST['limit'] ) ? absint( $_POST['limit'] ) : $query_vars['posts_per_page'];
		$query_vars['posts_per_page'] = isset( $args['limit'] ) ? absint( $args['limit'] ) : $query_vars['posts_per_page'];

		$query = new WP_Query( $query_vars );

		if ( $query->have_posts() ) {

			woocommerce_product_loop_start();

			while ( $query->have_posts() ) {
				$query->the_post();
				wc_get_template_part( 'content', 'product' );
			}

			woocommerce_product_loop_end();
		}

		wp_reset_postdata();
		if ( isset( $shoptimizer_load_previous ) && true === $shoptimizer_load_previous ) {
			return;
		} else {
			wp_die();
		}
	}

	/**
	 * Set pre posts
	 */
	public function set_pre_posts() {
		global $shoptimizer_load_previous, $wp_query;
		if ( ! is_shop() && ! is_product_category() && ! is_product_tag() ) {
			return;
		}
		$paged = max( 1, get_query_var( 'paged' ), get_query_var( 'page' ) );
		$fpage = isset( $_GET['fpage'] ) ? absint( $_GET['fpage'] ) : 0;
		if ( $fpage < 1 || $fpage > $wp_query->max_num_pages || $fpage >= $paged ) {
			return;
		}
		$shoptimizer_load_previous = true;

		$query_vars = $wp_query->query;
		if ( isset( $query_vars['paged'] ) ) {
			unset( $query_vars['paged'] );
		}

		for ( $i = $fpage; $i < $paged; $i++ ) {
			$args = array();

			$args['page']  = $i;
			$args['query'] = wp_json_encode( $query_vars );

			$this->ajax_load_more( $args );
		}	
	}

}

new Shoptimizer_Load_More();

endif;
