<?php
/**
 * Prodigy related products data mapper
 *
 * @version    2.7.0
 * @package    Prodigy
 * @subpackage Prodigy/includes
 */
namespace Prodigy\Includes\Frontend\Mappers;

use Prodigy\Includes\Content\Prodigy_Order_Parser;
use Prodigy\Includes\Content\Prodigy_Products_List_Parser;
use Prodigy\Includes\Content\Prodigy_Request_Maker;
use Prodigy\Includes\Frontend\Prodigy_Product_Template_Builder;
use Prodigy\Includes\Helpers\Prodigy_Cookies;
use Prodigy\includes\helpers\Prodigy_Elementor_Layouts;
use Prodigy\Includes\Helpers\Prodigy_Page;
use Prodigy\includes\models\Prodigy_Order;
use Prodigy\Includes\Prodigy;
use Prodigy\Includes\Prodigy_Pagination;
use Prodigy\Includes\Support\Customizer\Prodigy_Customizer;

defined( 'ABSPATH' ) || exit;

class Prodigy_Related_Products_Data_Mapper extends Prodigy_Main_Data_Mapper {

	const ORDER_ASC  = 'asc';
	const ORDER_DESC = 'desc';

	const UP_SELL    = 'up_sell';
	const CROSS_SELL = 'cross_sell';

	const UNLIMIT_PRODUCTS_NUMBER = - 1;

	/**
	 * @param array $options
	 *
	 * @return array
	 */
	public function get_default_parameters( array $options ): array {
		$options = $this->set_type_params( $options );
		$options = $this->set_order_params( $options );

		if ( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_GET['_wpnonce'] ) ), 'filter-nonce' ) ) {
			$options['page']  = isset( $_GET['pg'] ) ? sanitize_text_field( wp_unslash( $_GET['pg'] ) ) : 1;
			$options['query'] = build_query( $_GET ?? '' );
			$options          = $this->set_pagination_params( $options );
		}

		$product_ids = $this->get_type_of_products( $options );
		$heading     = apply_filters( 'prodigy_product_related_products_heading', 'Related products' );

		if ( ! empty( $options['style_image_ratio']['width'] ) && ! empty( $options['style_image_ratio']['height'] ) ) {
			$options['image_ratio'] = ( $options['style_image_ratio']['height'] / $options['style_image_ratio']['width'] ) * 100;
		}

		$options['products']        = $product_ids['data'] ?? array();
		$options['display']         = $options['display'] ?? self::SLIDER;
		$options['settings']        = $options ?? array();
		$options['image_ratio']     = Prodigy_Customizer::get_images_ratio();
		$options['sale_classname']  = 'prodigy-product-list__item-label';
		$options['heading']         = $options['style_content_heading_text'] ?? $heading ?? 'Related Products';
		$options['idWidget']        = $options['idWidget'] ?? '';
		$options['sale']            = $options['sale'] ?? '';
		$options['category']        = $options['category'] ?? true;
		$options['rating']          = $options['rating'] ?? true;
		$options['hide_arrows']     = $options['slider_hide_arrows'] ?? 'no';
		$options['placeholder_url'] = plugin_dir_url( PRODIGY_PLUGIN_PATH . 'web/admin/images/placeholder.png' ) . 'placeholder.png';

		return $options;
	}

	/**
	 * @param array $params
	 *
	 * @return array
	 */
	public function get_type_of_products( array $params ): array {
		if ( Prodigy_Elementor_Layouts::is_elementor_action() ) {
			$up_sell_product_ids = $this->set_products_for_elementor_page( $params );
		} elseif ( Prodigy_Page::is_cart() || ( ! empty( $params['order_token'] ) ) ) {
			$up_sell_product_ids = $this->set_products_for_cart_page( $params );
		} else {
			$up_sell_product_ids = $this->get_related_products( $params );
		}

		return $up_sell_product_ids;
	}

	/**
	 * @param array $params
	 *
	 * @return array
	 */
	public function set_type_params( array $params ): array {
		$params['type'] = $params['type'] ?? 'up-sell';

		if ( isset( $params['type'] ) ) {
			$params['type'] = $this->mappingTypeParams( $params['type'] );
		}

		return $params;
	}

	/**
	 * @param array $params
	 *
	 * @return array
	 */
	public function get_related_products( array $params ): array {
		if ( isset( $GLOBALS['prodigy_product'] ) ) {
			$products = array( $GLOBALS['prodigy_product']->get_remote_product_id() );
		} else {
			$products = $this->get_products_ids( Prodigy_Product_Template_Builder::get_random_products( self::UNLIMIT_PRODUCTS_NUMBER ) );
		}

		$up_sell_product_obj = $this->get_related_product( $products, $params );

		$products = ( new Prodigy_Products_List_Parser( $up_sell_product_obj ) )->get_products();

		return get_format_related_products( $products ?? array() );
	}

	/**
	 * @param array $products
	 *
	 * @return array
	 */
	public function get_products_ids( array $products ): array {
		$ids = array();
		if ( is_array( $products ) ) {
			foreach ( $products as $key => $product ) {
				$ids[ $key ] = get_post_meta( $product->ID, Prodigy::PRODIGY_REMOTE_PRODUCT_ID, true );
			}
		}

		return $ids;
	}

	/**
	 * @param array $params
	 *
	 * @return array
	 */
	public function set_products_for_elementor_page( array $params ): array {
		$products            = Prodigy_Product_Template_Builder::get_random_products();
		$remote_ids          = array_map(
			function ( $e ) {
				return get_post_meta( $e->ID, Prodigy::PRODIGY_REMOTE_PRODUCT_ID, true );
			},
			$products ?? array()
		);
		$relatedParams       = $this->get_related_products_id_url_params( $remote_ids );
		$paramsUrl           = $this->get_url_params( $params );
		$requestMaker        = Prodigy_Request_Maker::get_instance();
		$up_sell_product_obj = Prodigy_Page::prodigy_is_frontend()
			? $requestMaker->do_products_request( $relatedParams . $paramsUrl )
			: $requestMaker->do_admin_products_request( $relatedParams . $paramsUrl );

		return get_format_related_products( $up_sell_product_obj['data'] );
	}

	/**
	 * @param array $params
	 *
	 * @return array
	 */
	public function set_products_for_cart_page( array $params ): array {
		$order_token = $params['order_token'] ?? '';
		if ( Prodigy_Page::is_cart() ) {
			$cart_cookie = Prodigy_Cookies::get_user_cart_cookie();
			$order_token = ( new Prodigy_Order() )->get_order_token( $cart_cookie );
		}
		$product_ids = array();
		if ( $order_token ) {
			$order_data        = Prodigy_Request_Maker::get_instance()->do_order_request( $order_token );
			$remote_order_info = new Prodigy_Order_Parser( $order_data );

			switch ( $params['type'] ) {
				case self::UP_SELL:
					$product_ids = $remote_order_info->get_up_sell_products();
					break;
				case self::CROSS_SELL:
					$product_ids = $remote_order_info->get_cross_sell_products();
					break;
				default:
					$up_sell_product_ids    = $remote_order_info->get_up_sell_products();
					$cross_sell_product_ids = $remote_order_info->get_cross_sell_products();
					$product_ids            = array_merge( $up_sell_product_ids, $cross_sell_product_ids );
					break;
			}
		}

		if ( isset( $params['size'] ) && count( $product_ids ) > $params['size'] ) {
			$product_ids = array_slice( $product_ids, 0, $params['size'] );
		}

		return get_format_related_products( $product_ids );
	}

	/**
	 * @param array $params
	 *
	 * @return array
	 */
	public function set_order_params( array $params ): array {
		if ( isset( $params['orderby'] ) ) {
			$order = '';
			if ( isset( $params['order'] ) && $params['order'] === self::ORDER_DESC ) {
				$order = '-';
			}
			$params['sort'] = $order . $this->mappingOrderParams( $params['orderby'] );
		}

		return $params;
	}

	/**
	 * @param array $params
	 *
	 * @return array
	 */
	public function set_pagination_params( array $params ): array {
		$display = $params['display'] ?? self::SLIDER;

		$params['size'] = '';
		if ( $display === self::SLIDER && isset( $params['limit'] ) && $params['limit'] > 0 ) {
			$params['size'] = $params['limit'];
		} elseif ( $display === self::GRID ) {
			$params['size'] = Prodigy_Pagination::get_per_page_by_options();
		}

		if ( isset( $params['display'] ) && $params['display'] === self::GRID ) {
			$order_token          = isset( $_SERVER['HTTP_REFERER'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : false;
			$base_url             = remove_query_arg( 'pg', $order_token );
			$params['pagination'] = array(
				'pages'       => ! empty( $catalog_info ) ? Prodigy_Pagination::calculate_count_pages( (int) $catalog_info['products-count'], Prodigy_Pagination::get_per_page_by_options() ) : 1,
				'url'         => $base_url,
				'page'        => Prodigy_Pagination::get_current_page( (array) $params['query'] ),
				'page_number' => $params['page'],
			);
		}

		return $params;
	}

	/**
	 * @param string $order
	 *
	 * @return string
	 */
	public function mappingOrderParams( string $order ): string {
		$hsParams = array(
			'id'         => 'id',
			'created_at' => 'created_at',
			'date'       => 'created_at',
			'title'      => 'name',
			'rating'     => 'rating',
			'price'      => 'price',
		);

		return $hsParams[ $order ];
	}

	/**
	 * @param string $type
	 *
	 * @return string
	 */
	public function mappingTypeParams( string $type ): string {
		$hsParams = array(
			'cross-sell' => self::CROSS_SELL,
			'up-sell'    => self::UP_SELL,
			'both'       => '',
		);

		return $hsParams[ $type ];
	}


	/**
	 * @param array $products
	 *
	 * @return string
	 */
	public function get_related_products_id_url_params( array $products = array() ): string {
		if ( count( $products ) === 1 ) {
			return 'product_ids[]=' . $products[0];
		}

		if ( empty( $products ) ) {
			return '';
		}

		return 'product_ids[]=' . implode( '&product_ids[]=', $products );
	}

	/**
	 * @param array $params
	 *
	 * @return string
	 */
	public function get_url_params( array $params = array() ): string {
		$strUrl = '';

		if ( ! empty( $params['type'] ) ) {
			if ( $params['type'] === 'both' ) {
				$strUrl .= '&filters[][name]=bond_type&filters[][value]=cross_sell,up_sell';
			} else {
				$strUrl .= '&filters[][name]=bond_type&filters[][value]=' . $params['type'];
			}
		}

		if ( isset( $params['orderby'] ) ) {
			$sort = Prodigy_Main_Data_Mapper::mapping_sort_params( $params['orderby'] );

			if ( isset( $params['order'] ) ) {
				if ( strtolower( $params['order'] ) === strtolower( Prodigy_Products_Data_Mapper::DESCENDING_SORT ) ) {
					$sort = '-' . $sort;
				}
			}

			$strUrl .= '&sort=' . $sort;
		}

		if ( ! empty( $params['size'] ) ) {
			$strUrl .= '&page[size]=' . $params['size'];
		}

		if ( ! empty( $params['pg'] ) ) {
			$strUrl .= '&page[number]=' . (int) $params['pg'];
		} else {
			$strUrl .= '&page[number]=1';
		}

		return $strUrl;
	}

	/**
	 * @param array $products
	 * @param array $params
	 *
	 * @return array
	 */
	public function get_related_product( array $products = array(), array $params = array() ): array {
		$cache_key     = md5( wp_json_encode( array_merge( $products, array( $params['type'] ?? '' ) ) ) );
		$relatedParams = $this->get_related_products_id_url_params( $products );
		$paramsUrl     = $this->get_url_params( $params );

		return Prodigy_Request_Maker::get_instance()->do_related_products_request( $relatedParams . $paramsUrl, $cache_key );
	}

	/**
	 * @param array $products
	 *
	 * @return string
	 */
	public function get_key( array $products = array() ): string {
		if ( empty( $products ) ) {
			return hash( 'sha256', 'all' );
		}

		return hash( 'sha256', implode( '', $products ) );
	}
}
