<?php
/**
 * Manage the block rendering
 *
 * @package YITH\DynamicPricingAndDiscounts\Classes
 */

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

/**
 * The class
 */
class YWDPD_Dynamic_Rule_Products_Block extends YWDPD_Render_Block {
	/**
	 * Block attributes
	 *
	 * @var array
	 */
	protected $attributes = array(
		'columns'           => 4,
		'rows'              => 1,
		'ruleType'          => '',
		'includeAll'        => true,
		'ruleIds'           => array(),
		'contentVisibility' => array(
			'image'  => true,
			'title'  => true,
			'price'  => true,
			'rating' => true,
			'button' => true,
		),
	);

	/**
	 * Parse attributes.
	 *
	 * @param array $attributes Attributes.
	 *
	 * @return array
	 */
	protected function parse_attributes( $attributes ) {
		$attributes = parent::parse_attributes( $attributes );

		if ( is_string( $attributes['ruleIds'] ) ) {
			$attributes['ruleIds'] = explode( ',', $attributes['ruleIds'] );
		}

		$dynamic_rule_types = array(
			'bogo',
			'special_offer',
			'discount_whole',
			'category_discount',
		);
		if ( ! in_array( $attributes['ruleType'], $dynamic_rule_types, true ) ) {
			$attributes['ruleIds'] = array();
		}

		$attributes['columns']                     = max( 1, absint( $attributes['columns'] ) );
		$attributes['rows']                        = max( 1, absint( $attributes['rows'] ) );
		$attributes['includeAll']                  = yith_plugin_fw_is_true( $attributes['includeAll'] );
		$attributes['contentVisibility']['image']  = yith_plugin_fw_is_true( $attributes['contentVisibility']['image'] );
		$attributes['contentVisibility']['title']  = yith_plugin_fw_is_true( $attributes['contentVisibility']['title'] );
		$attributes['contentVisibility']['price']  = yith_plugin_fw_is_true( $attributes['contentVisibility']['price'] );
		$attributes['contentVisibility']['rating'] = yith_plugin_fw_is_true( $attributes['contentVisibility']['rating'] );
		$attributes['contentVisibility']['button'] = yith_plugin_fw_is_true( $attributes['contentVisibility']['button'] );

		return $attributes;
	}

	/**
	 * Return the rule type to show
	 *
	 * @return string
	 */
	public function get_rule_type() {
		return $this->attributes['ruleType'];
	}

	/**
	 * Return the rule ids to show
	 *
	 * @return array
	 */
	public function get_rule_ids() {
		return $this->attributes['ruleIds'];
	}

	/**
	 * Get the columns
	 *
	 * @return int
	 */
	public function get_columns() {
		return $this->attributes['columns'];
	}

	/**
	 * Get the rows
	 *
	 * @return int
	 */
	public function get_rows() {
		return $this->attributes['rows'];
	}

	/**
	 * Check if the image should be shown in the product loop
	 *
	 * @return bool
	 */
	public function image_is_visible() {
		return $this->attributes['contentVisibility']['image'];
	}

	/**
	 * Check if include all rule type in the query
	 *
	 * @return bool
	 */
	public function include_all_rules() {
		return $this->attributes['includeAll'];
	}

	/**
	 * Check if the add to cart button should be shown in the product loop
	 *
	 * @return bool
	 */
	public function add_to_cart_is_visible() {
		return $this->attributes['contentVisibility']['button'];
	}

	/**
	 * Check if the product title should be shown in the product loop
	 *
	 * @return bool
	 */
	public function title_is_visible() {
		return $this->attributes['contentVisibility']['title'];
	}

	/**
	 * Check if the product price should be shown in the product loop
	 *
	 * @return bool
	 */
	public function price_is_visible() {
		return $this->attributes['contentVisibility']['price'];
	}

	/**
	 * Check if the rating should be shown in the product loop
	 *
	 * @return bool
	 */
	public function rating_is_visible() {
		return $this->attributes['contentVisibility']['rating'];
	}

	/**
	 * Render the block
	 *
	 * @return void
	 * @throws Exception The exception.
	 */
	public function render() {

		if ( '' !== $this->get_rule_type() ) {
			wp_enqueue_style('wc-blocks-style-all-products' );
			$rule_ids   = $this->include_all_rules() ? array() : $this->get_rule_ids();
			$data_store = WC_Data_Store::load( 'ywdpd_dynamic_rules' );
			if ( count( $rule_ids ) === 0 ) {

				$rule_ids = $data_store->query(
					array(
						'type'    => $this->get_rule_type(),
						'enabled' => 'yes',
						'fields'  => 'rule_id',
					)
				);
			}

			$rule_ids = $this->filter_valid_rule_for_user( $rule_ids );
			$per_page = $this->get_columns() * $this->get_rows();
			// phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$current_page = isset( $_GET['product-page'] ) ? sanitize_text_field( intval( $_GET['product-page'] ) ) : 1;
			$offset       = ( $current_page - 1 ) * $per_page;
			$pagination   = '';
			if ( count( $rule_ids ) > 0 ) {
				$totals = $data_store->query(
					array(
						'rule__in' => $rule_ids,
						'enabled'  => 'yes',
						'object'   => 'product',
						'fields'   => 'count',
					)
				);
				if ( $totals > $per_page ) {
					$pagination_args = array(
						'total'   => ceil( $totals / $per_page ),
						'current' => $current_page,
						'base'    => esc_url_raw( add_query_arg( 'product-page', '%#%', false ) ),
						'format'  => '?product-page=%#%',
					);
					ob_start();
					wc_get_template( 'loop/pagination.php', $pagination_args );
					$pagination = ob_get_clean();
				}
				$products = $data_store->query(
					array(
						'rule__in' => $rule_ids,
						'enabled'  => 'yes',
						'object'   => 'product',
						'limit'    => $per_page,
						'offset'   => $offset,
					)
				);

				if ( count( $products ) > 0 ) {
					echo sprintf(
						'<div class="%s"><ul class="wc-block-grid__products">%s</ul>%s</div>',
						esc_attr( $this->get_container_classes() ),
						implode( '', array_map( array( $this, 'render_product' ), $products ) ),
						$pagination
					);
				} else {
					if ( $this->is_preview() ) {
						echo '<p>' . __( 'No products were found that matched your selection.', 'ywdpd' ) . '</p>';
					}
				}
			} else {
				$this->maybe_render_blank_state();
			}
		} else {
			$this->maybe_render_blank_state();
		}
	}

	/**
	 * Render the blank state
	 *
	 * @return void
	 */
	public function maybe_render_blank_state() {
		if ( $this->is_blank_state_allowed() ) {
			$this->render_blank_state();
		}
	}

	/**
	 * Return the valid rules for the current user
	 *
	 * @param array $rule_ids The rule ids.
	 *
	 * @return array
	 */
	public function filter_valid_rule_for_user( $rule_ids ) {
		if ( ! $this->is_preview() ) {
			$new_ids = array();
			foreach ( $rule_ids as $rule_id ) {
				$rule = ywdpd_get_rule( $rule_id );
				if ( $rule->is_valid() ) {
					$new_ids[] = $rule_id;
				}
			}
			$rule_ids = $new_ids;
		}

		return $rule_ids;
	}

	/**
	 * Get the list of classes to apply to this block.
	 *
	 * @return string space-separated list of classes.
	 */
	protected function get_container_classes() {
		$classes = array(
			'woocommerce',
			'wc-block-grid',
			'ywdpd-block-dynamic-products',
			"has-{$this->get_columns()}-columns",
		);

		if ( $this->get_rows() > 1 ) {
			$classes[] = 'has-multiple-rows';
		}

		if ( ! empty( $this->attributes['className'] ) ) {
			$classes[] = $this->attributes['className'];
		}

		return implode( ' ', $classes );
	}

	/**
	 * Render a single products.
	 *
	 * @param \WC_Product $product Product object.
	 *
	 * @return string Rendered product output.
	 */
	protected function render_product( $product ) {
		if ( ! $product || ! $product->is_visible() ) {
			return '';
		}
		$data = (object) array(
			'permalink' => esc_url( $product->get_permalink() ),
			'image'     => $this->get_image_html( $product ),
			'title'     => $this->get_title_html( $product ),
			'rating'    => $this->get_rating_html( $product ),
			'price'     => $this->get_price_html( $product ),
			'badge'     => $this->get_sale_badge_html( $product ),
			'button'    => $this->get_button_html( $product ),
		);

		/**
		 * Filters the HTML for products in the grid.
		 *
		 * @param string      $html    Product grid item HTML.
		 * @param array       $data    Product data passed to the template.
		 * @param \WC_Product $product Product object.
		 *
		 * @return string Updated product grid item HTML.
		 *
		 * @since 2.2.0
		 */
		return apply_filters(
			'woocommerce_blocks_product_grid_item_html',
			"<li class=\"wc-block-grid__product\">
				<a href=\"{$data->permalink}\" class=\"wc-block-grid__product-link\">
					{$data->image}
					{$data->title}
				</a>
				{$data->badge}
				{$data->price}
				{$data->rating}
				{$data->button}
			</li>",
			$data,
			$product
		);
	}

	/**
	 * Get the product image.
	 *
	 * @param \WC_Product $product Product.
	 *
	 * @return string
	 */
	protected function get_image_html( $product ) {
		if ( ! $this->image_is_visible() ) {
			return '';
		}

		$attr = array(
			'alt' => '',
		);

		if ( $product->get_image_id() ) {
			$image_alt = get_post_meta( $product->get_image_id(), '_wp_attachment_image_alt', true );
			$attr      = array(
				'alt' => ( $image_alt ? $image_alt : $product->get_name() ),
			);
		}

		return '<div class="wc-block-grid__product-image">' . $product->get_image( 'woocommerce_thumbnail', $attr ) . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
	}

	/**
	 * Get the product title.
	 *
	 * @param \WC_Product $product Product.
	 *
	 * @return string
	 */
	protected function get_title_html( $product ) {
		if ( ! $this->title_is_visible() ) {
			return '';
		}

		return '<div class="wc-block-grid__product-title">' . wp_kses_post( $product->get_title() ) . '</div>';
	}

	/**
	 * Render the rating icons.
	 *
	 * @param WC_Product $product Product.
	 *
	 * @return string Rendered product output.
	 */
	protected function get_rating_html( $product ) {
		if ( ! $this->rating_is_visible() ) {
			return '';
		}
		$rating_count = $product->get_rating_count();
		$average      = $product->get_average_rating();

		if ( $rating_count > 0 ) {
			return sprintf(
				'<div class="wc-block-grid__product-rating">%s</div>',
				wc_get_rating_html( $average, $rating_count ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
			);
		}

		return '';
	}

	/**
	 * Get the price.
	 *
	 * @param \WC_Product $product Product.
	 *
	 * @return string Rendered product output.
	 */
	protected function get_price_html( $product ) {
		if ( ! $this->price_is_visible() ) {
			return '';
		}

		return sprintf(
			'<div class="wc-block-grid__product-price price">%s</div>',
			wp_kses_post( $product->get_price_html() )
		);
	}

	/**
	 * Get the sale badge.
	 *
	 * @param \WC_Product $product Product.
	 *
	 * @return string Rendered product output.
	 */
	protected function get_sale_badge_html( $product ) {
		if ( ! $this->price_is_visible() ) {
			return '';
		}

		if ( ! $product->is_on_sale() ) {
			return;
		}

		return '<div class="wc-block-grid__product-onsale">
			<span aria-hidden="true">' . esc_html__( 'Sale', 'woocommerce' ) . '</span>
			<span class="screen-reader-text">' . esc_html__( 'Product on sale', 'woocommerce' ) . '</span>
		</div>';
	}

	/**
	 * Get the button.
	 *
	 * @param \WC_Product $product Product.
	 *
	 * @return string Rendered product output.
	 */
	protected function get_button_html( $product ) {
		if ( ! $this->add_to_cart_is_visible() ) {
			return '';
		}

		return '<div class="wp-block-button wc-block-grid__product-add-to-cart">' . $this->get_add_to_cart( $product ) . '</div>';
	}

	/**
	 * Get the "add to cart" button.
	 *
	 * @param \WC_Product $product Product.
	 *
	 * @return string Rendered product output.
	 */
	protected function get_add_to_cart( $product ) {
		$attributes = array(
			'aria-label'       => $product->add_to_cart_description(),
			'data-quantity'    => '1',
			'data-product_id'  => $product->get_id(),
			'data-product_sku' => $product->get_sku(),
			'rel'              => 'nofollow',
			'class'            => 'wp-block-button__link ' . ( function_exists( 'wc_wp_theme_get_element_class_name' ) ? wc_wp_theme_get_element_class_name( 'button' ) : '' ) . ' add_to_cart_button',
		);

		if (
			$product->supports( 'ajax_add_to_cart' ) &&
			$product->is_purchasable() &&
			( $product->is_in_stock() || $product->backorders_allowed() )
		) {
			$attributes['class'] .= ' ajax_add_to_cart';
		}

		return sprintf(
			'<a href="%s" %s>%s</a>',
			esc_url( $product->add_to_cart_url() ),
			wc_implode_html_attributes( $attributes ),
			esc_html( $product->add_to_cart_text() )
		);
	}

	/**
	 * Retrieve blank state params.
	 *
	 * @return array
	 */
	public function get_blank_state_params() {
		return array(
			'icon_url' => YITH_YWDPD_URL . '/assets/icons/price-rule.svg',
			'message'  => __( 'You have no dynamic rule yet.', 'ywdpd' ),
		);
	}
}
