<?php

/**
 * WP Channels Class.
 *
 * @package WP Product Feed Manager/Data/Classes
 * @version 1.6.0
 */

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

if ( ! class_exists( 'WPPFM_Channel' ) ) :

	/**
	 * Channel Class
	 */
	class WPPFM_Channel {
		/**
		 * Placeholder for the Channel Classes
		 *
		 * @var string
		 */
		private $_channels;

		public function __construct() {
			// WPPFM_CHANNEL_RELATED
			$this->_channels = array(
				new Wppfm_Channel_Info( '0', 'usersetup', 'Free User Setup' ),
				new Wppfm_Channel_Info( '1', 'google', 'Google Merchant Centre', 'https://support.google.com/merchants/answer/188924?sjid=17852146859618914984-EU&visit_id=638328859471105636-940801196&rd=1', 'https://support.google.com/merchants/answer/7052112?hl=en' ),
				new Wppfm_Channel_Info( '2', 'bing', 'Bing (Microsoft) Shopping', 'https://help.ads.microsoft.com/#apex/ads/en/51105/1', 'https://help.ads.microsoft.com/apex/index/3/en/51084' ),
				new Wppfm_Channel_Info( '3', 'beslis', 'Beslis.nl' ),
				new Wppfm_Channel_Info( '4', 'pricegrabber', 'PriceGrabber' ),
				new Wppfm_Channel_Info( '5', 'shopping', 'Shopping.com (eBay)' ),
				new Wppfm_Channel_Info( '6', 'amazon', 'Amazon product ads' ),
				new Wppfm_Channel_Info( '7', 'connexity', 'Connexity' ),
				new Wppfm_Channel_Info( '8', 'become', 'Become' ),
				// Become has been taken over by Connexity, https://merchants.become.com/DataFeedSpecification.html links to Connexity
				new Wppfm_Channel_Info( '9', 'nextag', 'Nextag' ),
				new Wppfm_Channel_Info( '10', 'kieskeurig', 'Kieskeurig.nl' ),
				new Wppfm_Channel_Info( '11', 'vergelijk', 'Vergelijk.nl' ),
				new Wppfm_Channel_Info( '12', 'koopjespakker', 'Koopjespakker.nl' ),
				new Wppfm_Channel_Info( '13', 'avantlink', 'AvantLink' ),
				new Wppfm_Channel_Info( '14', 'zbozi', 'Zbozi', 'https://napoveda.zbozi.cz/en/starting-to-advertise/', 'https://napoveda.zbozi.cz/en/xml-feed-2/specification/' ),
				new Wppfm_Channel_Info( '15', 'comcon', 'Commerce Connector' ),
				new Wppfm_Channel_Info( '16', 'facebook', 'Facebook', 'https://business.facebook.com/commerce_manager/get_started/', 'https://www.facebook.com/business/help/120325381656392?id=725943027795860' ),
				new Wppfm_Channel_Info( '17', 'bol', 'Bol.com' ),
				new Wppfm_Channel_Info( '18', 'adtraction', 'Adtraction', 'https://adtraction.com/advertisers', 'https://www.wpmarketingrobot.com/system/wp-content/uploads/2023/10/Adtraction_datafeedspecification.pdf' ),
				new Wppfm_Channel_Info( '19', 'ricardo', 'Ricardo.ch' ),
				new Wppfm_Channel_Info( '20', 'ebay', 'eBay' ),
				new Wppfm_Channel_Info( '21', 'shopzilla', 'Shopzilla' ),
				new Wppfm_Channel_Info( '22', 'converto', 'Converto' ),
				new Wppfm_Channel_Info( '23', 'idealo', 'Idealo' ),
				new Wppfm_Channel_Info( '24', 'heureka', 'Heureka', 'https://heureka.group/cz-en/for-brands/', 'https://www.heurekashopping.com/resources/attachments/p0/40/xml-filespecification.pdf' ),
				new Wppfm_Channel_Info( '25', 'pepperjam', 'Pepperjam' ),
				new Wppfm_Channel_Info( '26', 'galaxus_data', 'Galaxus Product Data' ),
				new Wppfm_Channel_Info( '27', 'galaxus_properties', 'Galaxus Product Properties' ),
				new Wppfm_Channel_Info( '28', 'galaxus_stock_pricing', 'Galaxus Product Stock Pricing' ),
				new Wppfm_Channel_Info( '29', 'vivino', 'Vivino' ),
				new Wppfm_Channel_Info( '30', 'snapchat', 'Snapchat Product Catalog', 'https://businesshelp.snapchat.com/s/topic/0TO0y000000YVd8GAG/catalogs?language=en_US', 'https://businesshelp.snapchat.com/s/article/product-catalog-specs?language=en_US' ),
				new Wppfm_Channel_Info( '31', 'pinterest', 'Pinterest', 'https://help.pinterest.com/en/business/article/before-you-get-started-with-catalogs', '' ),
				new Wppfm_Channel_Info( '32', 'vivino_xml', 'Vivino XML', 'https://help.vivino.com/s/article/How-does-Vivino-pull-my-inventory?language=en_US', 'https://vivino.slab.com/public/posts/vivino-feed-creation-guidelines-9gq0o3dg' ),
				new Wppfm_Channel_Info( '33', 'idealo_xml', 'Idealo XML', 'https://partner.idealo.com/uk/learning-center/faq-technical-integration', 'https://idealo.github.io/csv-importer/en/csv/' ),
				new Wppfm_Channel_Info( '34', 'x_shopping_manager', 'Twitter Shopping', 'https://business.twitter.com/en/products/shopping/shopping-manager.html', 'https://business.twitter.com/en/help/shopping-specs.html' ),
				new Wppfm_Channel_Info( '35', 'instagram_shopping', 'Instagram Shopping', 'https://business.instagram.com/shopping/?content_id=IE6I4Ax2NPXa0CM', 'https://www.facebook.com/business/help/161324715892485' ),
				new Wppfm_Channel_Info( '36', 'whatsapp_business', 'WhatsApp Business', 'https://business.whatsapp.com/products/business-app-features', 'https://www.facebook.com/business/help/161324715892485' ),
				new Wppfm_Channel_Info( '37', 'tiktok_catalog', 'TikTok Catalog', 'https://getstarted.tiktok.com/gofulltiktok?lang=en', 'https://ads.tiktok.com/help/article/catalog-product-parameters?lang=en' ),
				new Wppfm_Channel_Info( '38', 'atalanda', 'Atalanda', 'https://atalanda.com/mitmachen', 'https://atalanda.com/dev#google_xml' ),
				new Wppfm_Channel_Info( '39', 'reddit', 'Reddit Catalog', 'https://business.reddithelp.com/helpcenter/articles/Knowledge/catalogs', 'https://business.reddithelp.com/helpcenter/s/article/catalog-requirements' ),
				new Wppfm_Channel_Info( '40', 'chatgpt', 'ChatGpt', 'https://developers.openai.com/commerce', 'https://developers.openai.com/commerce/specs/feed' ),
				new Wppfm_Channel_Info( '996', 'marketingrobot_tsv', 'Custom TSV Export' ),
				new Wppfm_Channel_Info( '997', 'marketingrobot_txt', 'Custom TXT Export' ),
				new Wppfm_Channel_Info( '998', 'marketingrobot_csv', 'Custom CSV Export' ),
				new Wppfm_Channel_Info( '999', 'marketingrobot', 'Custom XML Export' ),
			);
		}

		/**
		 * Returns channel data from a specific channel
		 *
		 * @param string $channel_name channel name
		 *
		 * @return string Channel class
		 */
		public function get_active_channel_details( $channel_name ) {
			foreach ( $this->_channels as $channel ) {
				if ( $channel->channel_short === $channel_name ) {
					return $channel;
				}
			}

			return false;
		}

		/**
		 * Returns a channel short name from a specific channel, or false if the name was not found.
		 *
		 * @param string $channel_id channel id
		 *
		 * @return string|bool Channel class
		 */
		public function get_channel_short_name( $channel_id ) {
			foreach ( $this->_channels as $channel ) {
				if ( $channel->channel_id === $channel_id ) {
					return sanitize_file_name( (string) $channel->channel_short );
				}
			}

			return false;
		}

		/**
		 * Returns a channel name from a specific channel, or false if the name was not found.
		 *
		 * @param string $channel_id channel id
		 *
		 * @return string|bool Channel class
		 */
		public function get_channel_name( $channel_id ) {
			foreach ( $this->_channels as $channel ) {
				if ( $channel->channel_id === $channel_id ) {
					return (string) $channel->channel_name;
				}
			}

			return false;
		}

		/**
		 * Returns the installed channel names.
		 *
		 * @return array The installed channel names.
		 */
		public function get_installed_channel_names() {
			$file_class = new WPPFM_File();

			return $file_class->get_installed_channels_from_file();
		}

		/**
		 * Returns the channel info link.
		 *
		 * @param string $channel_short_name The channel short name.
		 *
		 * @return bool The channel info link.
		 */
		public function get_channel_info_link( $channel_short_name ) {
			foreach ( $this->_channels as $channel ) {
				if ( $channel->channel_short === $channel_short_name ) {
					return $channel->channel_info_link;
				}
			}

			return false;
		}

		/**
		 * Returns the channel specifications link.
		 *
		 * @param string $channel_short_name The channel short name.
		 *
		 * @return bool The channel specifications link.
		 */
		public function get_channel_specifications_link( $channel_short_name ) {
			foreach ( $this->_channels as $channel ) {
				if ( $channel->channel_short === $channel_short_name ) {
					return $channel->channel_specifications_link;
				}
			}

			return false;
		}

		/**
		 * Removes a channel from the server.
		 *
		 * @param string $channel The channel to remove.
		 * @param string $nonce   The nonce.
		 */
		public function remove_channel( $channel, $nonce ) {
			if ( wp_verify_nonce( $nonce, 'delete-channel-nonce' ) ) {
				$this->remove_channel_source( $channel );
			}
		}

		/**
		 * Updates a channel from the server.
		 *
		 * @param string $channel_short_name The channel short name.
		 * @param string $code               The channel code.
		 * @param string $nonce              The nonce.
		 */
		public function update_channel( $channel_short_name, $code, $nonce ) {
			if ( wp_verify_nonce( $nonce, 'update-channel-nonce' ) ) {
				$this->update_channel_source( $channel_short_name, $code );
			} else {
				wppfm_write_log_file( sprintf( 'Failed to update channel %s because then nonce was not accepted. Given nonce = %s', $channel_short_name, $nonce ) );
			}
		}

		/**
		 * Installs a channel from the server.
		 *
		 * @param string $channel The channel to install.
		 * @param string $code    The channel code.
		 * @param string $nonce   The nonce.
		 */
		public function install_channel( $channel, $code, $nonce ) {
			if ( wp_verify_nonce( $nonce, 'install-channel-nonce' ) ) {
				$this->install_channel_source( $channel, $code );
			} else {
				wppfm_write_log_file( sprintf( 'Failed to install channel %s because then nonce was not accepted. Given nonce = %s', $channel, $nonce ) );
			}
		}

		/**
		 * Returns the channels from the server
		 *
		 * @return array|WP_Error The channels from the server
		 */
		public function get_channels_from_server() {
			$url = trailingslashit( WPPFM_EDD_SL_STORE_URL ) . 'wpmr/channels/channels.php';

			$response = wp_remote_post(
				$url,
				array(
					'body' => array(
						'unique-site-id' => trim( get_option( 'wppfm_lic_key' ) ),
						'item_name'      => WPPFM_EDD_SL_ITEM_NAME,
					),
				)
			);

			// @since 2.3.0
			// @since 3.11.0 - Added a wp_remote_retrieve_response_code check.
			if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
				wppfm_handle_wp_errors_response(
					$response,
					sprintf(
						/* translators: %s: url to the wp marketingrobot server */
						__(
							'2832 - Failed to connect with the wp marketingrobot server. Please wait a few minutes and try again. If the issue persists, open a support ticket at %s.',
							'wp-product-feed-manager'
						),
						WPPFM_SUPPORT_PAGE_URL
					)
				);
			}

			return $response;
		}

		/**
		 * Returns the number of channel updates available from the server
		 *
		 * @param bool $channel_updated Flag indicating if a channel has been updated
		 *
		 * @return int|false The number of updates available, or false on failure
		 */
		public function get_number_of_channel_updates_from_server( $channel_updated ) {
			//@since 3.7.0. Only display channel updates available if the user chooses to update the channels manually
			if ( 'true' === get_option( 'wppfm_manual_channel_update', 'false' ) ) {
				return 0;
			}

			if ( gmdate( 'Ymd' ) === get_option( 'wppfm_channel_update_check_date' ) ) { // Only check once a day
				if ( $channel_updated ) {
					wppfm_decrease_update_ready_channels();
				}

				return get_option( 'wppfm_channels_to_update' );
			} else {
				$response = $this->get_channels_from_server();

				if ( ! is_wp_error( $response ) ) {
					$available_channels = json_decode( $response['body'] );

					if ( $available_channels ) {
						$installed_channels_names = $this->get_installed_channel_names();

						$this->add_status_data_to_available_channels( $available_channels, $installed_channels_names, false );

						$stored_count = $this->count_updatable_channels( $available_channels );

						$count = $channel_updated ? ( $stored_count - 1 ) : $stored_count;
						update_option( 'wppfm_channels_to_update', max( $count, 0 ) );
						update_option( 'wppfm_channel_update_check_date', gmdate( 'Ymd' ) );

						return $count;
					}
				} else {
					wppfm_handle_wp_errors_response(
						$response,
						sprintf(
							/* translators: %s: url to the support page */
							__(
								'2141 - Your WooCommerce Product Feed Manager plugin is unable to check for channel updates. This could be due to a temporary problem with our server. If this message does not clear in 15 minutes, please open a support ticket at %s for support on this issue.',
								'wp-product-feed-manager'
							),
							WPPFM_SUPPORT_PAGE_URL
						)
					);

					return false;
				}
			}

			return 0;
		}

		/**
		 * Adds status data to the available channels
		 *
		 * @param array $available_channels The available channels
		 * @param array $installed_channels The installed channels
		 * @param bool  $updated            The updated flag
		 */
		public function add_status_data_to_available_channels( $available_channels, $installed_channels, $updated ) {
			for ( $i = 0; $i < count( $available_channels ); $i ++ ) {
				if ( in_array( $available_channels[ $i ]->short_name, $installed_channels, true ) ) {
					$available_channels[ $i ]->status = 'installed';

					$available_channels[ $i ]->installed_version = $available_channels[ $i ]->short_name === $updated ? $available_channels[ $i ]->version
						: $this->get_channel_file_version( $available_channels[ $i ]->short_name, 0 );
				} else {
					$available_channels[ $i ]->status            = 'not installed';
					$available_channels[ $i ]->installed_version = '0';
				}
			}
		}

		public function add_channel_info_links_to_channels( $available_channels ) {
			for ( $i = 0; $i < count( $available_channels ); $i ++ ) {
				$available_channels[ $i ]->info_link           = $this->get_channel_info_link( $available_channels[ $i ]->short_name );
				$available_channels[ $i ]->specifications_link = $this->get_channel_specifications_link( $available_channels[ $i ]->short_name );
			}
		}

		/**
		 * Returns the name of the channel for a specific feed.
		 *
		 * @param string $feed_id The feed id.
		 *
		 * @since 2.20.0
		 * @return string The name of the channel
		 */
		public function get_channel_name_from_feed_id( $feed_id ) {
			$queries_class = new WPPFM_Queries();

			$feed_data = $queries_class->get_feed_row( $feed_id );
			return $this->get_channel_name( $feed_data->channel_id );
		}

		/**
		 * Returns the short name of the channel for a specific feed.
		 *
		 * @param string $feed_id The feed id.
		 *
		 * @since 2.20.0
		 * @return string The short name of the channel
		 */
		public function get_channel_short_name_from_feed_id( $feed_id ) {
			$queries_class = new WPPFM_Queries();

			$feed_data = $queries_class->get_feed_row( $feed_id );
			return $this->get_channel_short_name( $feed_data->channel_id );
		}

		/**
		 * Returns the version of the channel file.
		 *
		 * @param string $channel_name  The channel name.
		 * @param int    $rerun_counter The rerun counter.
		 * @param bool   $silent        The silent flag.
		 *
		 * @return string The version of the channel file
		 */
		public function get_channel_file_version( $channel_name, $rerun_counter, $silent = false ) {
			if ( $rerun_counter < 3 ) {
				if ( class_exists( 'WPPFM_' . ucfirst( $channel_name ) . '_Feed_Class' ) ) {
					$class_var = 'WPPFM_' . ucfirst( $channel_name ) . '_Feed_Class';

					$channel_class = new $class_var();

					return $channel_class->get_version();
				} else {
					// reset the registered channels in the channel table
					$db_class = new WPPFM_Database_Management();
					$db_class->reset_channel_registration();

					include_channels(); // include the channel classes

					$rerun_counter ++;

					return $this->get_channel_file_version( $channel_name, $rerun_counter, $silent );
				}
			} else {
				if ( wppfm_on_any_own_plugin_page() && ! $silent ) {
					/* translators: %s: Name of a channel */
					wppfm_show_wp_error( sprintf( __( 'Channel %s is not installed correctly. Please try to Deactivate and then Activate the Feed Manager Plugin in your Plugins page.', 'wp-product-feed-manager' ), $channel_name ) );
					wppfm_write_log_file( sprintf( 'Error: Channel %s is not installed correctly.', $channel_name ) );
				}

				return 'unknown';
			}
		}

		private function count_updatable_channels( $channel_data ) {
			$counter = 0;

			foreach ( $channel_data as $channel ) {
				if ( 'installed' === $channel->status && ( $channel->version > $channel->installed_version ) ) {
					$counter ++;
				}
			}

			return $counter;
		}

		/**
		 * Updates a channel on the server.
		 *
		 * @param string $channel_short_name The channel short name.
		 * @param string $code               The channel code.
		 */
		private function update_channel_source( $channel_short_name, $code ) {
			$file_class = new WPPFM_File();
			$ftp_class  = new WPPFM_Channel_FTP();

			// remove the outdated channel source files from the server
			$file_class->delete_channel_source_files( $channel_short_name );

			$get_result = $ftp_class->get_channel_source_files( $channel_short_name, $code );

			// get the update files from wp marketingrobot.com
			if ( false !== $get_result ) {
				// unzip the file
				$file_class->unzip_channel_file( $channel_short_name );

				// register the update
				wppfm_decrease_update_ready_channels();
			}
		}

		/**
		 * Removes a channel from the server.
		 *
		 * @param string $channel_short The channel short name.
		 */
		private function remove_channel_source( $channel_short ) {
			$data_class = new WPPFM_Data();
			$file_class = new WPPFM_File();

			// get the channel id that needs to be removed
			$channel_id = $data_class->get_channel_id_from_short_name( $channel_short );

			// unregister the channel
			wp_dequeue_script( 'wppfm_' . $channel_short . '-source-script' );

			if ( $channel_id ) {
				// remove channel related feed files
				$file_class->delete_channel_feed_files( $channel_id );

				// remove any channel related feed data and feed meta
				$data_class->delete_channel_feeds( $channel_id );
			}

			// remove the channel from the feedmanager_channel table
			$data_class->delete_channel( $channel_short );

			// remove the channel source files from the server
			$file_class->delete_channel_source_files( $channel_short );
		}

		/**
		 * Installs a channel from the server.
		 *
		 * @param string $channel_name The channel name.
		 * @param string $code         The channel code.
		 */
		private function install_channel_source( $channel_name, $code ) {
			$ftp_class  = new WPPFM_Channel_FTP();
			$file_class = new WPPFM_File();
			$data_class = new WPPFM_Data();

			if ( wppfm_plugin_version_supports_channel( $channel_name ) ) {
				// Get the update files from wp marketingrobot.com.
				$get_result = $ftp_class->get_channel_source_files( $channel_name, $code );

				if ( false !== $get_result ) {
					$ftp_class->register_channel_download( $channel_name ); // @since 3.13.0.

					// Unzip the file.
					$file_class->unzip_channel_file( $channel_name );

					// Register the new channel.
					$channel_details = $this->get_active_channel_details( $channel_name );

					if ( false !== $channel_details ) {
						$data_class->register_channel( $channel_name, $channel_details );
					} else {
						wppfm_write_log_file( sprintf( 'Unable to register channel %s', $channel_name ) );
					}
				} else {
					wppfm_write_log_file(
						sprintf(
							'Could not get the %s channel file from the server. Get_result message is %s.',
							$channel_name,
							false
						)
					);
				}
			} else {
				wppfm_show_wp_warning(
					sprintf(
						/* translators: %s: Name of the selected channel */
						__(
							'Channel %s is not supported by your current plugin version. Please update your plugin to the latest version and try uploading this channel again.',
							'wp-product-feed-manager'
						),
						$channel_name
					),
				);
			}
		}
	}

	// end of WPPFM_Channel class

	class Wppfm_Channel_Info {
		public $channel_id;
		public $channel_short;
		public $channel_name;
		public $channel_info_link;
		public $channel_specifications_link;

		public function __construct( $id, $short, $name, $info_link = '', $specifications_link = '' ) {
			$this->channel_id                  = $id;
			$this->channel_short               = $short;
			$this->channel_name                = $name;
			$this->channel_info_link           = $info_link;
			$this->channel_specifications_link = $specifications_link;
		}
	}

	// end of Wppfm_Channel_Info class
endif;
