<?php
namespace Prodigy\Includes;

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

use Elementor\Plugin as ElementorPlugin;
use Prodigy\Admin\Prodigy_Admin;
use Prodigy\Admin\Prodigy_Admin_Attributes_List;
use Prodigy\Admin\Prodigy_Admin_Categories_List;
use Prodigy\Admin\Prodigy_Admin_Notification;
use Prodigy\Admin\Prodigy_Admin_Products_List;
use Prodigy\Admin\Prodigy_Admin_Settings;
use Prodigy\admin\Prodigy_Admin_Setup_Wizard;
use Prodigy\admin\Prodigy_Admin_Wizard;
use Prodigy\Includes\Api\V1\Prodigy_Api_Attributes;
use Prodigy\Includes\Api\V1\Prodigy_Api_Batch_Taxonomies;
use Prodigy\Includes\Api\V1\Prodigy_Api_Category;
use Prodigy\Includes\Api\V1\Prodigy_Api_Import;
use Prodigy\Includes\Api\V1\Prodigy_Api_Product;
use Prodigy\Includes\Api\V1\Prodigy_Api_Product_Review;
use Prodigy\Includes\Api\V1\Prodigy_Api_Settings;
use Prodigy\Includes\Api\V1\Prodigy_Api_Taxonomies;
use Prodigy\Includes\Api\V1\Prodigy_Install_Demo_Content;
use Prodigy\Includes\Content\Prodigy_Api_Client;
use Prodigy\Includes\Content\Prodigy_Request_Maker;
use Prodigy\includes\Content\Prodigy_User_Content;
use Prodigy\Includes\Frontend\Actions\Prodigy_Buy_Now;
use Prodigy\Includes\Frontend\Actions\Prodigy_Punchout_Return;
use Prodigy\Includes\Frontend\Blocks\Prodigy_Blocks;
use Prodigy\Includes\Frontend\Cart_Error_Handler;
use Prodigy\Includes\Frontend\Mappers\Prodigy_Active_Filter_Data_Mapper;
use Prodigy\Includes\Frontend\Mappers\Prodigy_Filter_Data_Mapper;
use Prodigy\Includes\Frontend\Mappers\Prodigy_Price_Filter_Data_Mapper;
use Prodigy\Includes\Frontend\Mappers\Prodigy_Shop_Products_Data_Mapper;
use Prodigy\Includes\Frontend\Pages\Prodigy_Cart_Page;
use Prodigy\Includes\Frontend\Pages\Prodigy_Page;
use Prodigy\Includes\Frontend\Pages\Prodigy_Product_Page;
use Prodigy\Includes\Frontend\Pages\Prodigy_Shop_Page;
use Prodigy\Includes\Frontend\Prodigy_Public;
use Prodigy\Includes\Frontend\Shortcodes\Pages\Prodigy_Short_Code_Cart_Page;
use Prodigy\Includes\Frontend\Shortcodes\Pages\Prodigy_Short_Code_Thank_You;
use Prodigy\Includes\Frontend\Shortcodes\Prodigy_Short_Code_Active_Filter;
use Prodigy\Includes\Frontend\Shortcodes\Prodigy_Short_Code_Attributes_Filter;
use Prodigy\Includes\Frontend\Shortcodes\Prodigy_Short_Code_Banner;
use Prodigy\Includes\Frontend\Shortcodes\Prodigy_Short_Code_Breadcrumbs_List;
use Prodigy\Includes\Frontend\Shortcodes\Prodigy_Short_Code_Cart;
use Prodigy\Includes\Frontend\Shortcodes\Prodigy_Short_Code_Categories;
use Prodigy\Includes\Frontend\Shortcodes\Prodigy_Short_Code_Categories_Filter;
use Prodigy\Includes\Frontend\Shortcodes\Prodigy_Short_Code_Category_Link;
use Prodigy\Includes\Frontend\Shortcodes\Prodigy_Short_Code_My_Account;
use Prodigy\Includes\Frontend\Shortcodes\Prodigy_Short_Code_Price_Filter;
use Prodigy\Includes\Frontend\Shortcodes\Prodigy_Short_Code_Products;
use Prodigy\Includes\Frontend\Shortcodes\Prodigy_Short_Code_Related_Products;
use Prodigy\Includes\Frontend\Shortcodes\Prodigy_Short_Code_Search;
use Prodigy\Includes\Helpers\Prodigy_Ajax;
use Prodigy\Includes\Helpers\Prodigy_Cookies;
use Prodigy\Includes\Helpers\Prodigy_Parameters;
use Prodigy\Includes\Helpers\Prodigy_Platform_Settings;
use Prodigy\Includes\Helpers\Prodigy_Url_Helper;
use Prodigy\Includes\Helpers\Prodigy_Widget_Options;
use Prodigy\Includes\Helpers\Prodigy_Wp_Cookie_Compatibility;
use Prodigy\Includes\Migrations\Prodigy_Migration;
use Prodigy\includes\models\Prodigy_Order;
use Prodigy\includes\models\Prodigy_Product_Attributes;
use Prodigy\Includes\Support\Addons\Elementor\Builder\Module;
use Prodigy\Includes\Support\Addons\Elementor\Classes\Prodigy_Manager;
use Prodigy\Includes\Support\Customizer\Prodigy_Customizer;
use Prodigy\Includes\Support\Prodigy_Themes_Support;
use Prodigy\Includes\Synchronization\Content\Prodigy_Process_Factory;
use Prodigy\includes\synchronization\cron\Prodigy_Cron_Scheduler;
use Prodigy\Includes\Synchronization\Prodigy_Synchronization;
use Prodigy\Includes\Widgets\Prodigy_Active_Filters_Widget;
use Prodigy\Includes\Widgets\Prodigy_Cart_Widget;
use Prodigy\Includes\Widgets\Prodigy_Categories_Widget;
use Prodigy\Includes\Widgets\Prodigy_Filters_Widget;
use Prodigy\Includes\Widgets\Prodigy_My_Account_Widget;
use Prodigy\Includes\Widgets\Prodigy_Price_Filter_Widget;
use Prodigy\Includes\Widgets\Prodigy_Search_Widget;

defined( 'ABSPATH' ) || exit;
require_once ABSPATH . 'wp-admin/includes/plugin.php';

/**
 * The core plugin class.
 *
 * Also maintains the unique identifier of this plugin as well as the current
 * version of the plugin.
 *
 * @version    2.8.3
 * @package    Prodigy
 * @subpackage Prodigy/includes
 */
class Prodigy {

	public const PLUGIN_NAME = 'prodigy-commerce';

	public const PRODIGY_POST_TYPE_DEFAULT = 'prodigy-product';

	public const PRODIGY_VARIATION_POST_TYPE = 'prodigy_variation';

	public const PRODIGY_TAXONOMY_CATEGORY_DEFAULT = 'prodigy-product-category';

	public const PRODIGY_TAXONOMY_TAG_DEFAULT = 'prodigy-product-tag';

	public const PRODIGY_TAXONOMY_BRAND_DEFAULT = 'prodigy-product-brand';

	public const PRODIGY_FIRST_CONNECTED_PRODUCT = 'pg_first_connected_product';

	public const PRODIGY_HOSTED_CATEGORY_RELATION = 'prodigy_hosted_category_relation';

	public const PRODIGY_HOSTED_TAG_RELATION = 'prodigy_tag_remote_id';

	public const APPEARANCE_MENUS_CHECKED_FIRST = 3;

	public const PRODIGY_DEFAULT_PRODUCT_SLUG = 'product';

	public const PRODIGY_DEFAULT_CATEGORY_SLUG = 'product-category';

	public const PRODIGY_DEFAULT_TAG_SLUG = 'product-tag';

	public const PRODIGY_DEFAULT_BRAND_SLUG = 'product-brand';

	public const PAGE_PRODIGY_ATTRIBUTES = '_page_prodigy_attributes';

	public const PAGE_PRODIGY_SETTINGS = '_page_prodigy_settings';

	public const PAGE_PRODIGY_CATEGORIES = '_page_prodigy_categories';

	public const PAGE_PRODIGY_PRODUCTS = '_page_prodigy_products';

	public const PRODIGY_REMOTE_PRODUCT_ID = 'prodigy_remote_product_id';

	public const PRODIGY_REMOTE_ATTRIBUTE_ID = 'prodigy_attribute_value_remote_id';
	/** @var array|string[] */
	private static array $widgets = array(
		Prodigy_Active_Filters_Widget::class,
		Prodigy_Cart_Widget::class,
		Prodigy_Categories_Widget::class,
		Prodigy_Filters_Widget::class,
		Prodigy_My_Account_Widget::class,
		Prodigy_Price_Filter_Widget::class,
		Prodigy_Search_Widget::class,
	);
	/** @var string */
	protected string $plugin_name;
	/** @var Prodigy_Loader */
	protected Prodigy_Loader $loader;
	/** @var Prodigy_User */
	private Prodigy_User $user;
	/** @var Prodigy_Wp_Cookie_Compatibility */
	private Prodigy_Wp_Cookie_Compatibility $wp_cookie_compatibility;
	/**
	 * @var \Prodigy\Includes\Prodigy_Cart
	 */
	private Prodigy_Cart $cart;
	/**
	 * @var \Prodigy\includes\models\Prodigy_Order
	 */
	private Prodigy_Order $order;

	/**
	 * Define the core functionality of the plugin.
	 *
	 * @throws \Exception
	 */
	public function __construct() {
		$this->plugin_name = self::PLUGIN_NAME;
		$this->user        = new Prodigy_User();
		$this->wp_cookie_compatibility = new Prodigy_Wp_Cookie_Compatibility();
		$this->order       = new Prodigy_Order();
		$this->cart        = new Prodigy_Cart( Prodigy_Request_Maker::get_instance(), $this->order, new Cart_Error_Handler() );
		$this->load_dependencies();
		$this->set_locale();
		if ( is_admin() ) {
			$this->define_admin_hooks();

		}
		$this->define_public_hooks();
		$this->set_elementor();

		add_action( 'init', array( $this, 'register_post_types' ) );
		add_action( 'init', array( $this, 'register_taxonomies' ) );
		add_action( 'init', array( $this, 'register_tags' ) );
		add_action( 'init', array( $this, 'register_brands' ) );
		add_action( 'init', array( $this, 'load_instances' ) );
		add_action( 'init', array( $this, 'includes' ) );
		add_action( 'init', array( $this, 'load_global_scripts' ) );
		add_action( 'init', array( $this, 'start_sync_process' ) );
		add_action( 'init', array( $this, 'prodigy_register_elementor' ) );
		add_action( 'init', array( $this, 'update_plugin_version' ) );
		add_action( 'init', array( $this, 'prodigy_set_cart_cookie' ) );
		add_action( 'init', array( $this, 'set_auth_user_logic' ) );
		add_action( 'init', array( $this, 'init_early_taxonomy_validation' ) );
		add_action( 'init', array( $this, 'init_cron_events' ) );

		add_action( 'widgets_init', array( $this, 'prodigy_register_widgets' ) );
		add_action( 'admin_notices', array( new Prodigy_Admin_Notification(), 'display_admin_notice' ) );
		add_action( 'admin_init', array( $this, 'sync_content' ), 999 );
		add_action( 'prodigy_after_register_post_type', array( $this, 'maybe_flush_rewrite_rules' ) );
		add_filter( 'widget_text', 'do_shortcode' );
		add_action( 'activated_plugin', array( $this, 'prodigy_activation_redirect' ) );
		add_filter(
			'get_user_option_metaboxhidden_nav-menus',
			array(
				$this,
				'custom_display_appearance_menus',
			),
			10,
			3
		);
		add_action( 'after_switch_theme', array( $this, 'customize_current_theme' ) );
		add_action( 'divi_extensions_init', array( $this, 'divi_initialize_extension' ) );
		add_filter( 'allowed_redirect_hosts', array( $this, 'allowed_prodigy_redirect_urls' ) );

		$filters = array(
			'script_loader_src',
			'style_loader_src',
		);

		foreach ( $filters as $filter ) {
			add_filter( $filter, array( $this, 'my_make_asset_url_relative' ), 999 );
		}

		$this->init_wp_rocket_compatibility();
	}

	/**
	 * Load the required dependencies for this plugin.
	 *
	 * Include the following files that make up the plugin:
	 *
	 * - Prodigy_Loader. Orchestrates the hooks of the plugin.
	 * - Prodigy_Admin. Defines all hooks for the admin area.
	 * - Prodigy_Public. Defines all hooks for the public side of the site.
	 *
	 * @since    2.0.0
	 * @access   private
	 */
	private function load_dependencies(): void {
		/**
		 * prodigy trait sidebar
		 */
		require_once PRODIGY_PLUGIN_PATH . 'includes/helpers/traits/trait-prodigy-sidebar.php';
		require_once PRODIGY_PLUGIN_PATH . 'includes/frontend/traits/trait-prodigy-mlc-charge.php';

		/**
		 * prodigy enums
		 */
		require_once PRODIGY_PLUGIN_PATH . 'includes/helpers/enums/prodigy-enums.php';

		/**
		 * prodigy global functions
		 */
		require_once PRODIGY_PLUGIN_PATH . 'includes/helpers/prodigy-core-functions.php';

		/**
		 *  Add support template functions
		 */
		require_once PRODIGY_PLUGIN_PATH . 'includes/frontend/prodigy-template-functions.php';
		/**
		 * Set template hooks
		 */
		require_once PRODIGY_PLUGIN_PATH . 'includes/frontend/prodigy-template-hooks.php';

		$this->loader = new Prodigy_Loader();
	}

	/**
	 * Define the locale for this plugin for internationalization.
	 *
	 * Uses the Prodigy_i18n class in order to set the domain and to register the hook
	 * with WordPress.
	 *
	 * @since    1.0.0
	 * @access   private
	 */
	private function set_locale(): void {
		$plugin_i18n = new Prodigy_i18n();

		$this->loader->add_action( 'plugins_loaded', $plugin_i18n, 'load_plugin_textdomain' );
	}

	/**
	 * Register all of the hooks related to the admin area functionality
	 * of the plugin.
	 *
	 * @since    1.0.0
	 * @access   private
	 */
	private function define_admin_hooks(): void {
		$plugin_admin = new Prodigy_Admin( $this->get_plugin_name(), PRODIGY_VERSION );

		$this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
		$this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
	}

	/**
	 * The name of the plugin used to uniquely identify it within the context of
	 * WordPress and to define internationalization functionality.
	 *
	 * @return    string    The name of the plugin.
	 * @since     1.0.0
	 */
	public function get_plugin_name() {
		return $this->plugin_name;
	}

	/**
	 * Register all of the hooks related to the public-facing functionality
	 * of the plugin.
	 *
	 * @since    1.0.0
	 * @access   private
	 */
	private function define_public_hooks(): void {
		$plugin_public = new Prodigy_Public( $this->get_plugin_name() );

		$this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_styles' );
		$this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' );
	}

	/**
	 * Init elementor engine
	 *
	 * @return void
	 */
	public function set_elementor() {
		if ( is_plugin_active( 'elementor-pro/elementor-pro.php' ) && did_action( 'elementor/loaded' ) ) {
			add_action( 'elementor/init', array( $this, 'init_elementor' ) );
			add_action( 'elementor/init', array( $this, 'prodigy_elementor_source' ) );
		}
	}

	/**
	 * Initialize WP Rocket compatibility
	 */
	private function init_wp_rocket_compatibility() {
		require_once PRODIGY_PLUGIN_PATH . 'includes/class-prodigy-wp-rocket-compatibility.php';
	}

	/**
	 * Refresh permalinks after change entity slugs
	 *
	 * @return void
	 */
	public static function maybe_flush_rewrite_rules(): void {
		if ( Prodigy_Widget_Options::$bool_mapper[ get_option( 'prodigy_queue_flush_rewrite_rules' ) ] ) {
			update_option( 'prodigy_queue_flush_rewrite_rules', 'no' );
			flush_rewrite_rules();
		}
	}

	/**
	 *
	 * Set specify styles for current theme
	 */
	public static function customize_current_theme(): void {
		new Prodigy_Themes_Support();
	}

	/**
	 * Get the current prodigy brand type (slug)
	 *
	 * @return string
	 */
	public static function get_prodigy_brand_type(): string {
		return self::PRODIGY_TAXONOMY_BRAND_DEFAULT;
	}

	/**
	 * Get the plugin url.
	 *
	 * @return string
	 */
	public static function plugin_url(): string {
		return untrailingslashit( plugins_url( '/', PRODIGY_PLUGIN_FILE ) );
	}

	/**
	 * Get prodigy pages list
	 *
	 * @return array
	 */
	public static function get_pages_list() {
		$screen_ids = array(
			self::get_prodigy_product_type(),
			self::get_prodigy_category_type(),
			self::get_prodigy_tag_type(),
			'edit-' . self::get_prodigy_product_type(),
			'edit-' . self::get_prodigy_category_type(),
			'edit-' . self::get_prodigy_tag_type(),
			self::get_prodigy_product_type() . self::PAGE_PRODIGY_ATTRIBUTES,
			self::get_prodigy_product_type() . self::PAGE_PRODIGY_SETTINGS,
			self::get_prodigy_product_type() . self::PAGE_PRODIGY_CATEGORIES,
			self::get_prodigy_product_type() . self::PAGE_PRODIGY_PRODUCTS,
		);

		return $screen_ids;
	}

	/**
	 * Get the current prodigy tag type (slug)
	 *
	 * @return string
	 */
	public static function get_prodigy_tag_type(): string {
		return self::PRODIGY_TAXONOMY_TAG_DEFAULT;
	}

	public static function refresh_permalink() {
		global $wp_rewrite;

		// Flush the rules and tell it to write htaccess
		$wp_rewrite->flush_rules( true );
	}

	/**
	 * Adaptation of script connections for single domain approach
	 *
	 * @param  string $src
	 *
	 * @return string
	 */
	public function my_make_asset_url_relative( string $src ): string {
		// Elementor screenshot proxy requires absolute URLs to fetch assets.
		if ( is_admin() || isset( $_GET['screenshot_proxy'] ) ) {
			return $src;
		}

		$host     = wp_parse_url( home_url(), PHP_URL_HOST );
		$src_host = wp_parse_url( $src, PHP_URL_HOST );
		if ( ! $src_host || strcasecmp( $src_host, $host ) !== 0 ) {
			return $src;
		}

		return wp_make_link_relative( $src );
	}

	/**
	 * @return void
	 */
	public function init_cron_events() {
		new Prodigy_Cron_Scheduler();
	}

	/**
	 * Allow Hosted System domain
	 *
	 * @param  array $hosts
	 *
	 * @return array
	 */
	public function allowed_prodigy_redirect_urls( array $hosts ): array {
		$hosts[] = sprintf(
			'%1$s.%2$s',
			get_option( 'pg_url_domain_hosted_system' ),
			PRODIGY_CHECKOUT_DOMAIN
		);

		return $hosts;
	}

	/**
	 * @throws \Exception
	 */
	public function set_auth_user_logic(): void {
		// Skip authentication logic for Elementor proxy requests
		// Hide elementor errors
		if ( isset( $_GET['screenshot_proxy'] ) ) {
			return;
		}

		if ( $this->user->is_logout_action() ) {
			return;
		}

		$user_logged_in    = Prodigy_User::is_logged_in();
		$require_login     = Prodigy_Platform_Settings::is_enable_login_option();
		$session_token     = Prodigy_Parameters::get_parameter( $_GET, 'session_token' );
		if ( empty( $session_token ) ) {
			$session_token = Prodigy_Parameters::get_parameter( $_POST, 'session_token' );
		}
		if ( empty( $session_token ) ) {
			$session_token = Prodigy_Parameters::get_parameter( $_REQUEST, 'session_token' );
		}
		if ( empty( $session_token ) ) {
			$session_token = Prodigy_Parameters::get_parameter( $_GET, 'sessionToken' );
		}
		if ( empty( $session_token ) ) {
			$session_token = Prodigy_Parameters::get_parameter( $_POST, 'sessionToken' );
		}
		if ( empty( $session_token ) ) {
			$session_token = Prodigy_Parameters::get_parameter( $_REQUEST, 'sessionToken' );
		}
		$has_session_token = is_string( $session_token ) && $session_token !== '';
		$request_uri       = Prodigy_Url_Helper::prodigy_get_request_uri();

		if (
			$has_session_token
			&& Prodigy_Cookies::has_cookie( Prodigy_User::PRODIGY_USER_PAIRED_SESSION_COOKIE_NAME )
			&& $session_token !== Prodigy_Cookies::get_cookie( Prodigy_User::PRODIGY_USER_PAIRED_SESSION_COOKIE_NAME )
		) {
			$refresh_key = Prodigy_Cookies::get_cookie( Prodigy_User::REFRESH_COOKIE_NAME );
			$this->user->hosted_system_logout_process( $refresh_key );
			$this->user->logout();
			$this->user->delete_user_cookie();

			$user_logged_in = false;
		}

		if ( $this->user->should_return_early( $user_logged_in, $require_login, $has_session_token ) ) {
			return;
		}

		if ( $user_logged_in ) {
			$this->user->get_user_info_from_hosted_system();
		} else {
			$this->user->handle_unauthenticated_user( $require_login, $request_uri );
		}
	}

	/** Init Divi plugin */
	public function divi_initialize_extension(): void {
		require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/divi/includes/Divi.php';
	}

	/** Set up migrations */
	public function update_plugin_version(): void {
		$migration = new Prodigy_Migration();
		$migration->runUpgradeProcess();
	}

	/** Init elementor */
	public function init_elementor(): void {
		require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/conditions/prodigy.php';
		require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/conditions/product-archive.php';
		require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/conditions/shop-page.php';
		require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/documents/product-archive.php';
		require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/documents/product.php';
		require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/module.php';
		require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/conditions/prodigy-post.php';
		require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/conditions/prodigy-product-names.php';
		require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/conditions/prodigy-taxonomy.php';
		require_once PRODIGY_PLUGIN_PATH . 'includes/support/addons/elementor/builder/conditions/prodigy-sub-taxonomy.php';

		new Module();
	}

	/**
	 * Start a content synchronization process
	 *
	 * @return void
	 * @throws Demo\Exception\Prodigy_Demo_Content_Exception
	 */
	public function start_sync_process(): void {
		// Skip sync process for Elementor proxy requests
		// Hide elementor errors
		if ( isset( $_GET['screenshot_proxy'] ) ) {
			return;
		}

		$page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';

		if ( $page === 'prodigy-setup' ) {
			return;
		}

		$uri = Prodigy_Url_Helper::prodigy_get_request_uri();
		if ( $uri === '/favicon.ico' ) {
			return;
		}

		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
			return;
		}

		$sync_type_to_start           = get_option( Prodigy_Synchronization::PRODIGY_PROCESS_TYPE );
		$sync_type_to_start_auto_sync = get_option( Prodigy_Synchronization::PRODIGY_PROCESS_TYPE_AUTO_SYNC );

		$sync = new Prodigy_Synchronization();
		if ( $sync_type_to_start === Prodigy_Synchronization::PRODIGY_DEMO_PROCESS ) {
			$sync->run_sync_process( Prodigy_Api_Client::SYNC_DEMO_URL, Prodigy_Synchronization::PRODIGY_DEMO_PROCESS );
			delete_option( Prodigy_Synchronization::PRODIGY_PROCESS_TYPE );

			return;
		}

		if ( $sync_type_to_start === Prodigy_Synchronization::PRODIGY_MANUAL_PROCESS ) {
			$sync->run_sync_process( Prodigy_Api_Client::SYNC_CONTENT_URL, Prodigy_Synchronization::PRODIGY_MANUAL_PROCESS );
			delete_option( Prodigy_Synchronization::PRODIGY_PROCESS_TYPE );

			return;
		}

		if ( $sync_type_to_start_auto_sync === Prodigy_Synchronization::PRODIGY_AUTO_SYNC ) {
			$sync->run_sync_process( Prodigy_Api_Client::SYNC_CONTENT_URL, Prodigy_Synchronization::PRODIGY_AUTO_SYNC );
			delete_option( Prodigy_Synchronization::PRODIGY_PROCESS_TYPE_AUTO_SYNC );

			return;
		}
	}

	/** Init sync process */
	public function sync_content(): void {
		new Prodigy_Process_Factory();
	}

	/** Init Elementor integration */
	public function prodigy_register_elementor(): void {
		if ( is_plugin_active( 'elementor/elementor.php' ) ) {
			require_once 'support/addons/elementor/prodigy.php';
		}
	}

	/**
	 * Rewrite elementor templates library
	 */
	public function prodigy_elementor_source(): void {
		include 'support/addons/elementor/classes/prodigy-manager.php';
		include 'support/addons/elementor/classes/prodigy-api.php';
		include 'support/addons/elementor/classes/prodigy-custom-source.php';

		ElementorPlugin::instance()->templates_manager = new Prodigy_Manager( ElementorPlugin::instance()->templates_manager );

		$this->enable_cloud_templates();
	}

	private function enable_cloud_templates(): void {
		add_action(
			'elementor/init',
			function () {
				add_filter( 'elementor/connect/is_connected', '__return_true', 999 );
				add_filter( 'elementor/connect/app/library/is_connected', '__return_true', 999 );
				add_filter( 'elementor/editor/is_cloud_templates_enabled', '__return_true', 999 );
				if ( class_exists( '\ElementorPro\Plugin' ) ) {
					add_filter( 'elementor_pro/editor/is_cloud_templates_enabled', '__return_true', 999 );
				}

				if ( class_exists( '\Elementor\Core\Common\Modules\Connect\Module' ) ) {
					$connect_module = \Elementor\Plugin::$instance->common->get_component( 'connect' );
					if ( $connect_module ) {
						$library_app = $connect_module->get_app( 'library' );
						if ( $library_app ) {
							add_filter( 'elementor/connect/app/library/is_connected', '__return_true', 999 );
						}
					}
				}
			},
			5
		);

		add_filter( 'elementor/connect/is_connected', '__return_true', 999 );
		add_filter( 'elementor/connect/app/library/is_connected', '__return_true', 999 );
		add_filter( 'elementor/editor/is_cloud_templates_enabled', '__return_true', 999 );

		if ( class_exists( '\ElementorPro\Plugin' ) ) {
			add_filter( 'elementor_pro/editor/is_cloud_templates_enabled', '__return_true', 999 );
		}

		add_filter( 'elementor/ajax/get_library_data', array( $this, 'filter_library_data_for_cloud_templates' ), 10, 2 );
	}

	public function filter_library_data_for_cloud_templates( $data ) {
		if ( is_array( $data ) ) {
			$data['cloud_templates_enabled'] = true;
			$data['is_connected']            = true;
		}

		return $data;
	}

	public function filter_elementor_ajax_response( $response ) {
		if ( is_array( $response ) && isset( $response['data'] ) ) {
			if ( is_array( $response['data'] ) ) {
				$response['data']['is_connected']            = true;
				$response['data']['cloud_templates_enabled'] = true;
			}
		}

		return $response;
	}

	/**
	 * Register widgets
	 */
	public function prodigy_register_widgets(): void {
		if ( isset( self::$widgets ) ) {
			foreach ( self::$widgets as $widget ) {
				register_widget( new $widget() );
			}
		}
	}

	/**
	 * @throws \Exception
	 */
	public function load_instances(): void {
		$request_maker = Prodigy_Request_Maker::get_instance();
		$error_handler = new Cart_Error_Handler();

		$api_listener = ( new Prodigy_Callback_Api_Listener(
			$this->order,
			$request_maker,
			$this->cart
		) );

		new Prodigy_Migration();

		if ( is_admin() ) {
			/** Admin part */
			if ( ! wp_doing_ajax() ) {
				new Prodigy_Admin_Setup_Wizard( $this->user );
			}

			new Prodigy_Admin_Products_List();
			new Prodigy_Admin_Categories_List();
			new Prodigy_Admin_Settings();
			new Prodigy_Admin_Attributes_List();
			new Prodigy_Install_Demo_Content();
			new Prodigy_Admin_Wizard();
		}

		/** Frontend part */
		new Prodigy_Themes_Support();
		new Prodigy_Page( $this->order, $request_maker, $this->cart, $api_listener );
		new Prodigy_Product_Page( $this->order, $request_maker, $this->cart, $api_listener );

		new Prodigy_Cart_Page(
			$this->order,
			$request_maker,
			$this->cart,
			$error_handler,
			$api_listener
		);

		$shop_product_data_mapper = new Prodigy_Shop_Products_Data_Mapper();
		$active_filter            = new Prodigy_Active_Filter_Data_Mapper();
		$filter_data_mapper       = new Prodigy_Filter_Data_Mapper();
		$short_code_active_filter = new Prodigy_Short_Code_Active_Filter();
		$price_filter             = new Prodigy_Price_Filter_Data_Mapper();

		new Prodigy_Shop_Page(
			$this->order,
			$request_maker,
			$this->cart,
			$api_listener,
			$shop_product_data_mapper,
			$active_filter,
			$filter_data_mapper,
			$short_code_active_filter,
			$price_filter
		);
		new Prodigy_Buy_Now(
			$request_maker,
			$this->order,
			$this->cart
		);

		new Prodigy_Punchout_Return();

		/** Shortcodes part */
		new Prodigy_Short_Code_Cart();
		new Prodigy_Short_Code_Attributes_Filter();
		new Prodigy_Short_Code_Price_Filter();
		new Prodigy_Short_Code_Active_Filter();
		new Prodigy_Short_Code_Breadcrumbs_List();
		new Prodigy_Short_Code_Categories();
		new Prodigy_Short_Code_Categories_Filter();
		new Prodigy_Short_Code_Category_Link();
		new Prodigy_Short_Code_My_Account();
		new Prodigy_Short_Code_Products();
		new Prodigy_Short_Code_Related_Products();
		new Prodigy_Short_Code_Search();
		new Prodigy_Short_Code_Cart_Page();
		new Prodigy_Short_Code_Thank_You();
		new Prodigy_Short_Code_Banner();

		/** Main part */
		new Prodigy_Customizer();
		new Prodigy_Blocks();
		new Prodigy_User_Content();

		/** API */
		new Prodigy_Api_Attributes();
		new Prodigy_Api_Category();
		new Prodigy_Api_Product();
		new Prodigy_Api_Taxonomies();
		new Prodigy_Product_Comments();
		new Prodigy_Api_Product_Review();
		new Prodigy_Api_Batch_Taxonomies();
		new Prodigy_Api_Import();
		new Prodigy_Api_Settings();

		/** Helpers */
		new Prodigy_Ajax();
	}

	/**
	 * Load global JS
	 */
	public function load_global_scripts(): void {
		wp_register_script(
			'global',
			dirname( plugin_dir_url( __FILE__ ) ) . '/web/global/global.js',
			array( 'jquery' ),
			PRODIGY_VERSION,
			false
		);
		wp_enqueue_script( 'global' );

		wp_localize_script(
			'global',
			'data',
			array(
				'site_url'         => get_site_url(),
				'url'              => admin_url( 'admin-ajax.php' ),
				'nonce'            => wp_create_nonce( 'prodigyajax-nonce' ),
				'post_type'        => self::get_prodigy_product_type(),
				'plugin_directory' => get_prodigy_plugin_directory_name(),
			)
		);
	}

	/**
	 * Get the current prodigy product type (slug)
	 *
	 * @return string
	 */
	public static function get_prodigy_product_type(): string {
		return self::PRODIGY_POST_TYPE_DEFAULT;
	}

	/**
	 * After installing the plugin, set the default field "Product categories" to active
	 * appearance->menus->screen-options
	 *
	 * @param $result
	 * @param $option
	 * @param $user
	 *
	 * @return array
	 */
	public function custom_display_appearance_menus( $result, $option, $user ) {
		$current_type_category = self::get_prodigy_category_type();
		if ( get_option( 'pg_appearance_menus_checked_first' ) < self::APPEARANCE_MENUS_CHECKED_FIRST ) {
			$prodigy_appearance_menus = (int) get_option( 'pg_appearance_menus_checked_first' );

			?>
					<script type="text/javascript">
				let type_category = <?php echo esc_html( $current_type_category ); ?>;
				jQuery(document).ready(function ($) {
					$('#add-' + type_category + '-hide').attr('checked', true);
				});
					</script>
			<?php

			if ( ! empty( $result ) && is_array( $result ) && in_array( 'add-' . $current_type_category, $result, true ) ) {
				$result = array_diff( $result, array( 'add-' . $current_type_category ) );
				update_user_meta( $user->ID, 'metaboxhidden_nav-menus', $result );
			}

			update_option( 'pg_appearance_menus_checked_first', ++$prodigy_appearance_menus );
		}

		return $result;
	}

	/**
	 * Get current prodigy category type (slug)
	 *
	 * @return string
	 */
	public static function get_prodigy_category_type(): string {
		return self::PRODIGY_TAXONOMY_CATEGORY_DEFAULT;
	}

	/**
	 * Redirect on wizard after activated plugin
	 *
	 * @param $plugin
	 */
	public function prodigy_activation_redirect( $plugin ): void {
		if ( $plugin === PRODIGY_PLUGIN_DIRECTORY_NAME . '/prodigy-commerce.php' ) {
			$nonce = wp_create_nonce( 'wizard-form' );

			$redirect_url = admin_url( 'index.php?page=prodigy-setup&_wpnonce=' . $nonce );

			wp_redirect( sanitize_url( $redirect_url ) );
			exit;
		}
	}

	/**
	 * @return void
	 * @throws \Exception
	 */
	public function prodigy_set_cart_cookie(): void {
		// Skip cart session setup for Elementor proxy requests
		// Hide elementor errors
		if ( isset( $_GET['screenshot_proxy'] ) ) {
			return;
		}

		$shop_page_uri = Prodigy_Url_Helper::prodigy_parse_request_uri();
		if ( ! is_admin() && substr_count( $shop_page_uri, 'api-listener' ) && ! Prodigy_User::is_logged_in() ) {
			$this->cart->set_cart_user_session();
		}
	}

	public function includes(): void {
		// Wizard.
		if ( isset( $_GET['page'] ) && $_GET['page'] === 'prodigy-setup' ) {
			require_once PRODIGY_PLUGIN_PATH . 'admin/class-prodigy-admin-setup-wizard.php';
		}

		if ( isset( $_GET['prodigy-clear-wizard'] ) && $_GET['prodigy-clear-wizard'] == 1 ) {
			update_option( Prodigy_Admin_Setup_Wizard::OPTION_STEP_WIZARD, Prodigy_Admin_Setup_Wizard::DEFAULT_STEP );
		}
	}

	/**
	 * Register prodigy post type
	 */
	public function register_post_types(): void {
		add_post_type_support( self::get_prodigy_product_type(), 'thumbnail' );

		$labels = array(
			'menu_name' => __( 'Prodigy', 'prodigy-commerce' ),
			'all_items' => __( 'Products', 'prodigy-commerce' ),
			'name'      => __( 'Prodigy Products', 'prodigy-commerce' ),
		);

		register_post_type(
			self::PRODIGY_POST_TYPE_DEFAULT,
			array(
				'labels'       => $labels,
				'description'  => '',
				'public'       => true,
				'hierarchical' => false,
				'supports'     => array( 'title', 'excerpt', 'thumbnail', 'comments' ),
				'taxonomies'   => array( self::PRODIGY_TAXONOMY_CATEGORY_DEFAULT, self::PRODIGY_TAXONOMY_TAG_DEFAULT ),
				'has_archive'  => false,
				'rewrite'      => array( 'slug' => self::get_prodigy_product_slug() ),
				'query_var'    => true,
				'menu_icon'    => 'dashicons-prodigy-logo',
			)
		);

		register_post_type(
			self::PRODIGY_VARIATION_POST_TYPE,
			array(
				'label'        => __( 'Variations', 'prodigy-commerce' ),
				'public'       => false,
				'hierarchical' => false,
				'supports'     => false,
				'rewrite'      => false,
			)
		);

		do_action( 'prodigy_after_register_post_type' );
	}

	/**
	 * Get actual post-slug
	 *
	 * @return false|mixed|void
	 */
	public static function get_prodigy_product_slug() {
		return get_option( 'pg_product_type_slug', self::PRODIGY_DEFAULT_PRODUCT_SLUG );
	}

	/**
	 * Register prodigy taxonomies.
	 */
	public function register_taxonomies(): void {
		if ( ! is_blog_installed() ) {
			return;
		}

		if ( taxonomy_exists( self::get_prodigy_category_type() ) ) {
			return;
		}

		$labels = array(
			'name'              => __( 'Prodigy Product Categories', 'prodigy-commerce' ),
			'singular_name'     => __( 'Prodigy Category', 'prodigy-commerce' ),
			'menu_name'         => __( 'Categories', 'prodigy-commerce' ),
			'search_items'      => __( 'Search Categories', 'prodigy-commerce' ),
			'all_items'         => __( 'All Categories', 'prodigy-commerce' ),
			'parent_item'       => __( 'Parent Category', 'prodigy-commerce' ),
			'parent_item_colon' => __( 'Parent Category', 'prodigy-commerce' ),
			'edit_item'         => __( 'Edit Category', 'prodigy-commerce' ),
			'update_item'       => __( 'Update Category', 'prodigy-commerce' ),
			'add_new_item'      => __( 'Add New Category', 'prodigy-commerce' ),
			'new_item_name'     => __( 'New Category Name', 'prodigy-commerce' ),
			'not_found'         => __( 'No Categories Found', 'prodigy-commerce' ),
		);

		$args = array(
			'hierarchical'      => true,
			'show_ui'           => true,
			'show_admin_column' => true,
			'show_in_rest'      => true,
			'query_var'         => true,
			'label'             => __( 'Categories', 'prodigy-commerce' ),
			'labels'            => $labels,
			'capabilities'      => array(
				'pg_manage_terms' => 'pg_manage_product_terms',
			),
			'rewrite'           => array(
				'slug' => self::get_prodigy_category_slug(),
			),
		);

		register_taxonomy( self::PRODIGY_TAXONOMY_CATEGORY_DEFAULT, array( self::PRODIGY_POST_TYPE_DEFAULT ), $args );

		$attributes = Prodigy_Product_Attributes::get_attribute_taxonomies();

		if ( ! empty( $attributes ) ) {
			foreach ( $attributes as $attribute ) {
				$args = array(
					'hierarchical'      => false,
					'show_ui'           => false,
					'show_admin_column' => false,
					'query_var'         => true,
				);

				register_taxonomy( $attribute->slug, array( self::PRODIGY_POST_TYPE_DEFAULT ), $args );
			}
		}
	}

	/**
	 * Get actual taxonomy slug
	 *
	 * @return false|mixed|void
	 */
	public static function get_prodigy_category_slug() {
		return get_option( 'pg_category_type_slug', self::PRODIGY_DEFAULT_CATEGORY_SLUG );
	}

	/**
	 *  Register prodigy tags
	 */
	public function register_tags(): void {
		$labels = array(
			'name'                       => __( 'Prodigy Product Tags', 'prodigy-commerce' ),
			'singular_name'              => __( 'Prodigy Tag', 'prodigy-commerce' ),
			'menu_name'                  => __( 'Tags', 'prodigy-commerce' ),
			'search_items'               => __( 'Search Tags', 'prodigy-commerce' ),
			'all_items'                  => __( 'All Tags', 'prodigy-commerce' ),
			'edit_item'                  => __( 'Edit Tag', 'prodigy-commerce' ),
			'update_item'                => __( 'Update Tag', 'prodigy-commerce' ),
			'add_new_item'               => __( 'Add New Tag', 'prodigy-commerce' ),
			'new_item_name'              => __( 'New Tag Name', 'prodigy-commerce' ),
			'popular_items'              => __( 'Popular Tags', 'prodigy-commerce' ),
			'separate_items_with_commas' => __( 'Separate tags with commas', 'prodigy-commerce' ),
			'add_or_remove_items'        => __( 'Add or remove tags', 'prodigy-commerce' ),
			'choose_from_most_used'      => __( 'Choose from the most used tags', 'prodigy-commerce' ),
			'not_found'                  => __( 'No tags found', 'prodigy-commerce' ),
		);

		$args = array(
			'hierarchical'      => false,
			'show_ui'           => true,
			'show_admin_column' => true,
			'query_var'         => true,
			'label'             => __( 'Product tags', 'prodigy-commerce' ),
			'labels'            => $labels,
			'capabilities'      => array(
				'pg_manage_terms' => 'pg_manage_product_terms',
			),
			'rewrite'           => array(
				'slug' => self::get_prodigy_tag_slug(),
			),
		);

		register_taxonomy( self::PRODIGY_TAXONOMY_TAG_DEFAULT, array( self::PRODIGY_POST_TYPE_DEFAULT ), $args );
	}

	/**
	 * Get actual tag slug
	 *
	 * @return false|mixed|void
	 */
	public static function get_prodigy_tag_slug() {
		return get_option( 'pg_tag_type_slug', self::PRODIGY_DEFAULT_TAG_SLUG );
	}

	/**
	 *  Register prodigy tags
	 */
	public function register_brands(): void {
		$args = array(
			'hierarchical'      => false,
			'show_ui'           => false,
			'show_admin_column' => false,
			'query_var'         => true,
			'label'             => __( 'Product brands', 'prodigy-commerce' ),
			'labels'            => array(),
			'rewrite'           => array(
				'slug' => self::get_prodigy_brand_slug(),
			),
		);

		register_taxonomy( self::PRODIGY_TAXONOMY_BRAND_DEFAULT, array( self::PRODIGY_POST_TYPE_DEFAULT ), $args );
	}

	/**
	 * Get actual taxonomy slug
	 *
	 * @return false|mixed|void
	 */
	public static function get_prodigy_brand_slug() {
		return get_option( 'pg_brand_type_slug', self::PRODIGY_DEFAULT_BRAND_SLUG );
	}

	/**
	 * Run the loader to execute all of the hooks with WordPress.
	 *
	 * @since    1.0.0
	 */
	public function run() {
		$this->loader->run();
	}

	/**
	 * The reference to the class that orchestrates the hooks with the plugin.
	 *
	 * @return    Prodigy_Loader    Orchestrates the hooks of the plugin.
	 * @since     1.0.0
	 */
	public function get_loader() {
		return $this->loader;
	}

	/**
	 * Initialize early taxonomy validation
	 */
	public function init_early_taxonomy_validation(): void {
		add_action( 'template_redirect', array( $this, 'validate_taxonomy_terms_early' ), 1 );
	}

	/**
	 * Validate taxonomy terms early in the request cycle
	 */
	public function validate_taxonomy_terms_early() {
		if ( is_admin() || wp_doing_ajax() || wp_doing_cron() ) {
			return;
		}

		// Skip validation for Elementor proxy requests
		// Hide elementor errors
		if ( isset( $_GET['screenshot_proxy'] ) ) {
			return;
		}

		Prodigy_Url_Helper::validate_prodigy_taxonomy_url();
	}
}
