<?php

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

/**
 * WooCommerce plugins integration
 */
class Permalink_Manager_WooCommerce {

	public function __construct() {
		add_action( 'init', array( $this, 'init_hooks' ), 99 );
		add_action( 'plugins_loaded', array( $this, 'init_early_hooks' ), 99 );
	}

	/**
	 * Add support for SEO plugins using their hooks
	 */
	function init_hooks() {
		if ( class_exists( 'WooCommerce' ) ) {
			add_filter( 'permalink_manager_filter_query', array( $this, 'woocommerce_detect' ), 8, 5 );
			add_filter( 'template_redirect', array( $this, 'woocommerce_checkout_fix' ), 9 );
			add_filter( 'permalink_manager_permastructs_fields', array( $this, 'woocommerce_permastructs_fields' ), 9 );

			if ( class_exists( 'Permalink_Manager_Pro_Functions' ) ) {
				if ( empty( $permalink_manager_options['general']['partial_disable']['post_types'] ) || ! in_array( 'shop_coupon', $permalink_manager_options['general']['partial_disable']['post_types'] ) ) {
					if ( is_admin() ) {
						add_filter( 'woocommerce_coupon_data_tabs', 'Permalink_Manager_Pro_Functions::woocommerce_coupon_tabs' );
						add_action( 'woocommerce_coupon_data_panels', 'Permalink_Manager_Pro_Functions::woocommerce_coupon_panel' );
						add_action( 'woocommerce_coupon_options_save', 'Permalink_Manager_Pro_Functions::woocommerce_save_coupon_uri', 9, 2 );
					}

					add_filter( 'request', 'Permalink_Manager_Pro_Functions::woocommerce_detect_coupon_code', 1, 1 );
				}
			} else {
				add_filter( 'permalink_manager_disabled_post_types', array( $this, 'woocommerce_coupon_uris' ), 9, 1 );
			}

			// WooCommerce Import/Export
			add_filter( 'woocommerce_product_export_product_default_columns', array( $this, 'woocommerce_csv_custom_uri_column' ), 9 );
			add_filter( 'woocommerce_product_export_product_column_custom_uri', array( $this, 'woocommerce_export_custom_uri_value' ), 9, 3 );

			add_filter( 'woocommerce_csv_product_import_mapping_options', array( $this, 'woocommerce_csv_custom_uri_column' ), 9 );
			add_filter( 'woocommerce_csv_product_import_mapping_default_columns', array( $this, 'woocommerce_csv_custom_uri_column' ), 9 );
			add_action( 'woocommerce_product_import_inserted_product_object', array( $this, 'woocommerce_csv_import_custom_uri' ), 9, 2 );

			add_action( 'woocommerce_product_duplicate', array( $this, 'woocommerce_generate_permalinks_after_duplicate' ), 9, 2 );
			add_filter( 'permalink_manager_filter_default_post_uri', array( $this, 'woocommerce_product_attributes' ), 5, 5 );

			if ( wp_doing_ajax() && class_exists( 'SitePress' ) ) {
				add_filter( 'permalink_manager_filter_final_post_permalink', array( $this, 'woocommerce_translate_ajax_fragments_urls' ), 9999, 3 );
			}

			// Make sure that the custom permalinks are not generated prematurely
			add_filter( 'woocommerce_rest_pre_insert_product_object', array( $this, 'woocommerce_delay_product_custom_permalink' ), 10, 3 );
			add_action( 'woocommerce_rest_insert_product_object', array( $this, 'woocommerce_set_custom_uri_after_rest_insert' ), 20, 3 );
		}

		// WooCommerce Wishlist Plugin
		if ( function_exists( 'tinv_get_option' ) ) {
			add_filter( 'permalink_manager_detect_uri', array( $this, 'ti_woocommerce_wishlist_uris' ), 15, 3 );
		}

		// WooCommerce Subscriptions
		if ( class_exists( 'WC_Subscriptions' ) ) {
			add_filter( 'permalink_manager_filter_final_post_permalink', array( $this, 'wcs_fix_subscription_links' ), 10, 3 );
		}
	}

	/**
	 * Some hooks must be called shortly after all the plugins are loaded
	 */
	public function init_early_hooks() {
		if ( class_exists( 'WooCommerce' ) ) {
			add_filter( 'woocommerce_get_endpoint_url', array( 'Permalink_Manager_Core_Functions', 'control_trailing_slashes' ), 9 );
			add_action( 'before_woocommerce_init', array( $this, 'woocommerce_declare_compatibility' ) );
		}
	}

	/**
	 * Fix query on WooCommerce shop page & disable the canonical redirect if WooCommerce query variables are set
	 */
	function woocommerce_detect( $query, $old_query, $uri_parts, $pm_query, $content_type ) {
		global $woocommerce, $pm_query;

		$shop_page_id = get_option( 'woocommerce_shop_page_id' );

		// WPML - translate shop page id
		$shop_page_id = apply_filters( 'wpml_object_id', $shop_page_id, 'page', true );

		// Fix shop page
		if ( get_theme_support( 'woocommerce' ) && ! empty( $pm_query['id'] ) && is_numeric( $pm_query['id'] ) && $shop_page_id == $pm_query['id'] ) {
			$query['post_type'] = 'product';
			unset( $query['pagename'] );
		}

		// Fix WooCommerce pages
		if ( ! empty( $woocommerce->query->query_vars ) ) {
			$query_vars = $woocommerce->query->query_vars;

			foreach ( $query_vars as $key => $val ) {
				if ( isset( $query[ $key ] ) ) {
					$query['do_not_redirect'] = 1;
					break;
				}
			}
		}

		return $query;
	}

	/**
	 * Redirects the user from the Shop archive to the Shop page if the user is not searching for anything
	 * Disable canonical redirect on "thank you" & another WooCommerce pages
	 */
	function woocommerce_checkout_fix() {
		global $wp_query, $pm_query, $permalink_manager_options;

		// Redirect from Shop archive to selected page
		if ( is_shop() && empty( $pm_query['id'] ) ) {
			$redirect_mode = ( ! empty( $permalink_manager_options['general']['redirect'] ) ) ? $permalink_manager_options['general']['redirect'] : false;
			$redirect_shop = apply_filters( 'permalink_manager_redirect_shop_archive', false );
			$shop_page     = get_option( 'woocommerce_shop_page_id' );

			if ( $redirect_mode && $redirect_shop && $shop_page && empty( $wp_query->query_vars['s'] ) ) {
				$shop_url = get_permalink( $shop_page );
				wp_safe_redirect( $shop_url, $redirect_mode );
				exit();
			}
		}

		if ( is_checkout() || ( function_exists( 'is_wc_endpoint_url' ) && is_wc_endpoint_url() ) ) {
			$wp_query->query_vars['do_not_redirect'] = 1;
		}
	}

	/**
	 * Separate WooCommerce custom post types & taxonomies in "Permastructures" screen
	 *
	 * @param array $fields
	 *
	 * @return array
	 */
	public function woocommerce_permastructs_fields( $fields ) {
		if ( is_array( $fields ) ) {
			$woocommerce_fields     = array( 'product' => 'post_types', 'product_tag' => 'taxonomies', 'product_cat' => 'taxonomies', 'product_brand' => 'taxonomies' );
			$woocommerce_attributes = wc_get_attribute_taxonomies();

			foreach ( $woocommerce_attributes as $woocommerce_attribute ) {
				$woocommerce_fields["pa_{$woocommerce_attribute->attribute_name}"] = 'taxonomies';
			}

			foreach ( $woocommerce_fields as $field => $field_type ) {
				if ( empty( $fields[ $field_type ]["fields"][ $field ] ) ) {
					continue;
				}

				$fields["woocommerce"]["fields"][ $field ] = $fields[ $field_type ]["fields"][ $field ];
				unset( $fields[ $field_type ]["fields"][ $field ] );
			}
		}

		return $fields;
	}

	/**
	 * Add "Coupons" to the list of excluded post types
	 *
	 * @param array $post_types
	 *
	 * @return array
	 */
	public function woocommerce_coupon_uris( $post_types ) {
		if ( is_array( $post_types ) ) {
			$post_types[] = 'shop_coupon';
		}

		return $post_types;
	}

	/**
	 * Generate a new custom permalink for duplicated product
	 *
	 * @param WC_Product $new_product The new product object.
	 * @param WC_Product $old_product The product that was duplicated.
	 */
	function woocommerce_generate_permalinks_after_duplicate( $new_product, $old_product ) {
		if ( ! empty( $new_product ) ) {
			$product_id = $new_product->get_id();

			// Ignore variations
			if ( $new_product->get_type() === 'variation' || Permalink_Manager_Helper_Functions::is_post_excluded( $product_id, true ) ) {
				return;
			}

			$custom_uri = Permalink_Manager_URI_Functions_Post::get_default_post_uri( $product_id, false, true );
			Permalink_Manager_URI_Functions::save_single_uri( $product_id, $custom_uri, false, true );
		}
	}

	/**
	 * If the URI contains %pa_attribute_name% tag, replace it with the value of the attribute
	 *
	 * @param string $default_uri The default custom permalink that WordPress would use for the post.
	 * @param string $slug The post slug.
	 * @param WP_Post $post The post object.
	 * @param string $post_name The post slug.
	 * @param bool $native_uri true if the URI is a native URI, false if it's a custom URI
	 *
	 * @return string The default custom permalink
	 */
	function woocommerce_product_attributes( $default_uri, $slug, $post, $post_name, $native_uri ) {
		// Do not affect native URIs
		if ( $native_uri ) {
			return $default_uri;
		}

		// Use only for products
		if ( empty( $post->post_type ) || $post->post_type !== 'product' ) {
			return $default_uri;
		}

		preg_match_all( "/%pa_(.[^\%]+)%/", $default_uri, $custom_fields );

		if ( ! empty( $custom_fields[1] ) ) {
			$product = wc_get_product( $post->ID );

			foreach ( $custom_fields[1] as $i => $custom_field ) {
				$attribute_name  = sanitize_title( $custom_field );
				$attribute_value = $product->get_attribute( $attribute_name );

				$default_uri = str_replace( $custom_fields[0][ $i ], Permalink_Manager_Helper_Functions::sanitize_title( $attribute_value ), $default_uri );
			}
		}

		return $default_uri;
	}

	/**
	 * Stop the plugin from generating the custom permalink for new WooCommerce product prematurely.
	 *
	 * @param WC_Data $data The product object.
	 * @param WP_REST_Request $request The REST API request object.
	 * @param bool $is_new_post Whether the product is newly created.
	 */
	function woocommerce_delay_product_custom_permalink( $data, $request, $is_new_post ) {
		add_filter( 'permalink_manager_pre_update_post_uri', '__return_null', 100 );

		return $data;
	}

	/**
	 * Sets a custom permalink for a WooCommerce product after it is inserted via the REST API.
	 *
	 * @param WC_Product $product The product object.
	 * @param WP_REST_Request $request The REST API request object.
	 * @param bool $is_new_post Whether the product is newly created.
	 */
	function woocommerce_set_custom_uri_after_rest_insert( $product, $request, $is_new_post ) {
		if ( $is_new_post && class_exists( 'Permalink_Manager_URI_Functions_Post' ) && method_exists( $product, 'get_id' ) ) {
			$product_id = $product->get_id();

			remove_filter( 'permalink_manager_pre_update_post_uri', '__return_null', 100 );

			$new_uri = Permalink_Manager_URI_Functions_Post::get_default_post_uri( $product_id );
			Permalink_Manager_URI_Functions_Post::save_uri( $product_id, $new_uri, $is_new_post );
		}
	}

	/**
	 * Check the current request is a WooCommerce AJAX request. If it is, check the translated page's URL should be returned
	 *
	 * @param string $permalink The full URL of the post
	 * @param WP_Post $post The post object
	 * @param string $old_permalink The original URL of the post.
	 *
	 * @return string The permalink is being returned.
	 */
	function woocommerce_translate_ajax_fragments_urls( $permalink, $post, $old_permalink ) {
		// Use it only if the permalinks are different
		if ( $permalink == $old_permalink || $post->post_type !== 'page' ) {
			return $permalink;
		}

		// A. Native WooCommerce AJAX events
		if ( ! empty( $_REQUEST['wc-ajax'] ) ) {
			$action = sanitize_title( $_REQUEST['wc-ajax'] );
		} // B. Shoptimizer theme
		else if ( ! empty( $_REQUEST['action'] ) ) {
			$action = sanitize_title( $_REQUEST['action'] );
		}

		// Allowed action names
		$allowed_actions = array( 'shoptimizer_pdp_ajax_atc', 'get_refreshed_fragments' );

		if ( ! empty( $action ) && in_array( $action, $allowed_actions ) ) {
			$translated_post_id = apply_filters( 'wpml_object_id', $post->ID, 'page' );
			$permalink          = ( $translated_post_id !== $post->ID ) ? get_permalink( $translated_post_id ) : $permalink;
		}

		return $permalink;
	}

	/**
	 * 4FA. Add a new column to the WooCommerce CSV Import/Export tool
	 *
	 * @param array $columns The array of columns to be displayed.
	 *
	 * @return array The $columns array.
	 */
	function woocommerce_csv_custom_uri_column( $columns ) {
		if ( ! is_array( $columns ) ) {
			return $columns;
		}

		$label = __( 'Custom URI', 'permalink-manager' );
		$key   = 'custom_uri';

		if ( current_filter() == 'woocommerce_csv_product_import_mapping_default_columns' ) {
			$columns[ $label ] = $key;
		} else {
			$columns[ $key ] = $label;
		}

		return $columns;
	}

	/**
	 * 4FB. Return the custom permalink of the product if it exists, otherwise return the default URI
	 *
	 * @param string $value The value of the column.
	 * @param WC_Product $product The product object.
	 * @param mixed $column_id The column ID.
	 *
	 * @return string The custom permalink or default permalink
	 */
	function woocommerce_export_custom_uri_value( $value, $product, $column_id ) {
		if ( empty( $value ) && ! empty( $product ) ) {
			$product_id = $product->get_id();

			// Get custom permalink or default permalink
			$value = Permalink_Manager_URI_Functions_Post::get_post_uri( $product_id );
		}

		return $value;
	}

	/**
	 * 4FC. Set the custom URI for the product using the value from CSV file, if not set use the default permalink
	 *
	 * @param WC_Product $product The product object.
	 * @param array $data The data array for the current row being imported.
	 */
	function woocommerce_csv_import_custom_uri( $product, $data ) {
		if ( ! empty( $product ) ) {
			$product_id = $product->get_id();

			// Ignore variations
			if ( $product->get_type() == 'variation' ) {
				return;
			}

			$current_uri = Permalink_Manager_URI_Functions::get_single_uri( $product_id, false, true );

			// A. Use default permalink if "Custom URI" is not set and did not exist before
			if ( empty( $current_uri ) && empty( $data['custom_uri'] ) ) {
				$custom_uri = Permalink_Manager_URI_Functions_Post::get_default_post_uri( $product_id, false, true );
			} else if ( ! empty( $data['custom_uri'] ) ) {
				$custom_uri = Permalink_Manager_Helper_Functions::sanitize_title( $data['custom_uri'] );
			} else {
				return;
			}

			Permalink_Manager_URI_Functions::save_single_uri( $product_id, $custom_uri, false, true );
		}
	}

	/**
	 * Declare support for 'High-Performance order storage (COT)' and other features in WooCommerce
	 */
	function woocommerce_declare_compatibility() {
		$features_util_class = '\Automattic\WooCommerce\Utilities\FeaturesUtil';

		if ( class_exists( $features_util_class ) && method_exists( $features_util_class, 'declare_compatibility' ) ) {
			$features = method_exists( $features_util_class, 'get_features' ) ? $features_util_class::get_features( true ) : array();

			foreach ( array_keys( $features ) as $feature ) {
				$features_util_class::declare_compatibility( $feature, PERMALINK_MANAGER_BASENAME );
			}
		}
	}

	/**
	 * Extract the Wishlist ID from the URI and add it to the $uri_parts array (WooCommerce Wishlist Plugin)
	 *
	 * @param array $uri_parts An array of the URI parts.
	 * @param string $request_url The URL that was requested.
	 * @param array $endpoints An array of all the endpoints that are currently registered.
	 *
	 * @return array The URI parts.
	 */
	function ti_woocommerce_wishlist_uris( $uri_parts, $request_url, $endpoints ) {
		$wishlist_pid = function_exists( 'tinv_get_option' ) ? tinv_get_option( 'general', 'page_wishlist' ) : '';

		// Find the Wishlist page URI
		if ( is_numeric( $wishlist_pid ) ) {
			$current_uri = Permalink_Manager_URI_Functions::get_single_uri( $wishlist_pid, false, true );

			if ( ! empty( $current_uri ) ) {
				$wishlist_uri = preg_quote( $current_uri, '/' );

				// Extract the Wishlist ID
				preg_match( "/^({$wishlist_uri})\/([^\/]+)\/?$/", $uri_parts['uri'], $output_array );

				if ( ! empty( $output_array[2] ) ) {
					$uri_parts['uri']            = $output_array[1];
					$uri_parts['endpoint']       = 'tinvwlID';
					$uri_parts['endpoint_value'] = $output_array[2];
				}
			}
		}

		return $uri_parts;
	}

	/**
	 * Keep the query strings appended to the product permalinks by WooCommerce Subscriptions
	 *
	 * @param string $permalink
	 * @param WP_Post $post
	 * @param string $old_permalink
	 *
	 * @return string
	 */
	function wcs_fix_subscription_links( $permalink, $post, $old_permalink ) {
		if ( ! empty( $post->post_type ) && $post->post_type == 'product' && strpos( $old_permalink, 'switch-subscription=' ) !== false ) {
			$query_arg = parse_url( $old_permalink, PHP_URL_QUERY );
			$permalink = "{$permalink}?{$query_arg}";
		}

		return $permalink;
	}
}