<?php

namespace MOWCPS\Common\Services\ProductDataServices;

use MOWCPS\Common\Models\Sync_Details_DAO;
use MOWCPS\Common\Models\Product_Sync_Audit_Model;
use MOWCPS\Common\Constants\Constants;
use MOWCPS\Common\Models\Setting_Model;
use MOWCPS\Common\Constants\Plugin_Filters;
use MOWCPS\Common\Services\Logging\Supplier_Logger;
use MOWCPS\Common\Handlers\SyncAnalytics\Sync_Analytics;
use MOWCPS\Common\Utils\Sync_Utils;

/**
 * Class Product_Data_Services
 */
class Product_Data_Services {

	/**
	 * Filter unsynced data.
	 *
	 * @param int   $supplier_id   Supplier ID.
	 * @param int   $connection_id Connection ID.
	 * @param array $product_data  Product data array.
	 * @param int   $batch_number  Current batch number.
	 *
	 * @return array Filtered product data array.
	 */
	public static function filter_unsynced_data( $supplier_id, $connection_id, $product_data, $batch_number ) {
		// temprory values for testing maybe get from DAO or need sql query.
		$batch_flag         = Sync_Details_DAO::get_instance()->get_batch_flag();
		$page_flag          = Sync_Details_DAO::get_instance()->get_page_flag();
		$batch_size         = Sync_Details_DAO::get_instance()->get_batch_size();
		$schedule_id        = Sync_Details_DAO::get_instance()->get_schedule_id();
		$sync_type          = Sync_Details_DAO::get_instance()->get_connection_sync_type( $connection_id );
		$connection_details = Sync_Details_DAO::get_instance()->get_connection_details( $connection_id );
		$connection_type    = $connection_details['type'] ?? Constants::CONNECTION_TYPE_API;

		if ( $batch_flag && $batch_size > 0 ) {
			Supplier_Logger::debug( $supplier_id, 'Processing batch ' . $batch_number . ' (batch size: ' . $batch_size . ' products)' );
		}
		// Check if using new batch-file system (batch-wise file storage).
		$using_batch_files = self::is_using_batch_file_system( $supplier_id, $connection_id, $batch_flag );

		$sync_analytics       = Sync_Details_DAO::get_instance()->get_connection_analytics( $supplier_id, $schedule_id, $connection_id );
		$total_product_parsed = $sync_analytics->total_product_parsed;

		$initial = true === $batch_flag ? ( ( $batch_number - 1 ) * $batch_size ) : $total_product_parsed;

		if ( true === $batch_flag ) {
			// This block only execute if batch flag is on.
			$last_batch_product_parsed = 0;
			$prev_batch                = false;

			$main_analytics_data        = Product_Sync_Audit_Model::get_sync_audit( $supplier_id, $schedule_id, $connection_id ); // Get the main analytics data.
			$batch_analytics_array      = Product_Sync_Audit_Model::get_sync_audit( $supplier_id, $schedule_id, $connection_id, $batch_number, true ); // Get all the batch analytics data.
			$main_additional_data_array = json_decode( $main_analytics_data->additional_data ?? '{}', true );
			unset( $main_analytics_data );

			if ( ! empty( $batch_analytics_array ) ) {
				$last_batch_analytics      = end( $batch_analytics_array );
				$last_batch_product_parsed = $last_batch_analytics->parsed_success;
				if ( count( (array) $batch_analytics_array ) >= $batch_number ) {
					$initial   += $batch_analytics_array[ $batch_number - 1 ]->parsed_success;
					$prev_batch = true;
					if ( isset( $main_additional_data_array['synced_variable_products_with_parent_attribute'] ) ) {
						$last_batch_product_parsed_array = json_decode( $batch_analytics_array[ $batch_number - 1 ]->additional_data, true );
						if ( isset( $last_batch_product_parsed_array['synced_variable_products_with_parent_attribute'] ) ) {
							$initial                   = $last_batch_product_parsed_array['synced_variable_products_with_parent_attribute'];
							$last_batch_product_parsed = $last_batch_product_parsed_array['synced_variable_products_with_parent_attribute'];
						}
						unset( $last_batch_product_parsed_array );
					}
				}
				unset( $last_batch_analytics );
			}

			$file_sync_details = Setting_Model::get_by_connection_and_operation( $connection_id, 'file-sync', array( 'configuration' => true ) );

			$last_batch_product_parsed = is_null( $last_batch_product_parsed ) ? 0 : (int) $last_batch_product_parsed;

			if ( has_filter( Plugin_Filters::FILTER_ALTER_PRODUCT_SYNC_AUDIT ) ) {
				$batch_completion_request = apply_filters(
					Plugin_Filters::FILTER_ALTER_PRODUCT_SYNC_AUDIT,
					array(
						'event_specifier'           => Plugin_Filters::EVENT_ALTER_INITIAL_AND_PREVIOUS_BATCH_VALUE,
						'supplier_id'               => $supplier_id,
						'connection_id'             => $connection_id,
						'initial'                   => $initial,
						'batch_flag'                => $batch_flag,
						'prev_batch'                => $prev_batch,
						'batch_number'              => $batch_number,
						'batch_size'                => $batch_size,
						'last_batch_product_parsed' => $last_batch_product_parsed,
					)
				);

				$initial    = $batch_completion_request['initial'];
				$prev_batch = $batch_completion_request['prev_batch'];

				// Allow filter to modify last_batch_product_parsed for suppliers like SNS Activewear.
				if ( isset( $batch_completion_request['last_batch_product_parsed'] ) ) {
					$last_batch_product_parsed = $batch_completion_request['last_batch_product_parsed'];
				}
				unset( $batch_completion_request );
			}
			$batch_additional_data_array = isset( $batch_analytics_array[ $batch_number - 1 ]->additional_data ) ? json_decode( $batch_analytics_array[ $batch_number - 1 ]->additional_data, true ) : array();
			$last_row_count              = (int) ( isset( $batch_additional_data_array['last_row_count'] ) ? $batch_additional_data_array['last_row_count'] : 0 );

			if ( ( Constants::CONNECTION_TYPE_FILE === $connection_type ) || ( ! empty( $file_sync_details['configuration']['file_in_batch'] ) && Constants::CONFIGURATION_ACTIVE === $file_sync_details['configuration']['file_in_batch'] ) ) {
				$return_array = array_slice( $product_data, $last_row_count, count( $product_data ), false );
				unset( $product_data );
				unset( $batch_analytics_array, $main_additional_data_array, $batch_additional_data_array, $file_sync_details, $sync_analytics, $connection_details );
				return $return_array;
			} elseif ( $using_batch_files ) {
				if ( $prev_batch && $last_batch_product_parsed > 0 ) {
					$return_array = array_slice( $product_data, $last_batch_product_parsed, count( $product_data ), false );
					Supplier_Logger::debug( $supplier_id, sprintf( 'Batch %d: Resuming from product %d (skipped %d already synced products)', $batch_number, $last_batch_product_parsed + 1, $last_batch_product_parsed ) );
					unset( $product_data );
				} else {
					$return_array = $product_data;
				}
				unset( $batch_analytics_array, $main_additional_data_array, $batch_additional_data_array, $file_sync_details, $sync_analytics, $connection_details );
			} elseif ( $prev_batch ) {
				$return_array = array_slice( $product_data, $initial, $batch_size - $last_batch_product_parsed, false );
				unset( $product_data );
				unset( $batch_analytics_array, $main_additional_data_array, $batch_additional_data_array, $sync_analytics, $connection_details );
			} else {
				$return_array = array_slice( $product_data, $initial, $batch_size, false );
				unset( $product_data );
				unset( $batch_analytics_array, $main_additional_data_array, $batch_additional_data_array, $sync_analytics, $connection_details );
			}
		} elseif ( Constants::OUTBOUND === $sync_type ) {
			// This block only execute if sync type is outbound.
			$batch_analytics_array      = Product_Sync_Audit_Model::get_sync_audit( $supplier_id, $schedule_id, $connection_id, $batch_number, true );

			if ( ! empty( $batch_analytics_array ) ) {
				$last_batch_analytics             = end( $batch_analytics_array );
				$last_batch_additional_data_array = json_decode( $last_batch_analytics->additional_data, true );
				$last_batch_product_parsed        = (int) ( isset( $last_batch_additional_data_array['last_row_count'] ) ? (int) $last_batch_additional_data_array['last_row_count'] : 0 );
				supplier_Logger::debug( $supplier_id, sprintf( 'Outbound Sync - Batch %d: Last batch parsed product count: %d', $batch_number, $last_batch_product_parsed ) );
				unset( $last_batch_analytics );
			}
			if ( isset( $last_batch_product_parsed ) && $last_batch_product_parsed > 0 ) {
				$return_array = array_slice( $product_data, $last_batch_product_parsed, count( $product_data ), false );
				Supplier_Logger::debug( $supplier_id, sprintf( 'Outbound Sync - Batch %d: Resuming from product %d (skipped %d already synced products)', $batch_number, $last_batch_product_parsed + 1, $last_batch_product_parsed ) );
				unset( $product_data );
			} else {
				$return_array = array_slice( $product_data, 0, count( $product_data ), false );
				unset( $product_data );
				unset( $sync_analytics, $connection_details );
			}
		} else {
			// This block only execute if sync type is page sync without batch.
			$is_flag_on = true === $page_flag;

			$batch_analytics_array = Product_Sync_Audit_Model::get_sync_audit( $supplier_id, $schedule_id, $connection_id, $batch_number, true ); // Get all the batch analytics data.
			$main_analytics_data   = Product_Sync_Audit_Model::get_sync_audit( $supplier_id, $schedule_id, $connection_id ); // Get the main analytics data.

			$last_batch_filter_product_count = 0;
			$last_batch_product_parsed       = 0;

			if ( ! empty( $batch_analytics_array ) ) {
				$last_batch_analytics             = end( $batch_analytics_array );
				$last_batch_additional_data_array = json_decode( $last_batch_analytics->additional_data, true );
				$last_batch_filter_product_count  = $last_batch_additional_data_array['product_per_page'];
				$last_batch_product_parsed        = $last_batch_analytics->total_parsed;
				$main_additional_data_array       = json_decode( $main_analytics_data->additional_data, true );

				if ( isset( $main_additional_data_array['synced_variable_products_with_parent_attribute'] ) ) {
					$last_batch_product_parsed = $main_additional_data_array['synced_variable_products_with_parent_attribute'];
				}
				unset( $last_batch_analytics, $last_batch_additional_data_array, $main_additional_data_array );
			}
			unset( $main_analytics_data );

			$is_parsed_correct = (int) $last_batch_product_parsed === (int) $last_batch_filter_product_count;
			if ( ( $is_flag_on && $is_parsed_correct ) ) {
				// All products from the previous page were synced successfully, and page sync is enabled => send full product list.
				$return_array = $product_data;
			} else {
				// Either not all products from the previous page were synced successfully, or sync type is normal i.e. batch and page sync is off — so we send only the remaining products which were not synced from the last batch.
				$return_array = array_slice( $product_data, $last_batch_product_parsed, count( $product_data ) - $last_batch_product_parsed, false );
				unset( $product_data );
			}
			unset( $batch_analytics_array, $sync_analytics, $connection_details );
		}
		Sync_Utils::trigger_garbage_collection();

		return $return_array;
	}

	/**
	 * Check if using new batch-file system.
	 *
	 * @param int  $supplier_id   Supplier ID.
	 * @param int  $connection_id Connection ID.
	 * @param bool $batch_flag    Whether batch processing is enabled.
	 * @return bool True if using batch-file system, false otherwise.
	 */
	private static function is_using_batch_file_system( $supplier_id, $connection_id, $batch_flag ) {
		if ( ! $batch_flag ) {
			return false;
		}
		$file_directory_path = trailingslashit( MOWCPS_PLUGIN_DIR ) . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'external-supplier' . DIRECTORY_SEPARATOR . 'api-response';
		$batch_file_pattern  = sprintf( 'sync_%s_%s_batch_*.json', $supplier_id, $connection_id );
		$batch_files         = glob( $file_directory_path . DIRECTORY_SEPARATOR . $batch_file_pattern );
		$result              = ( false !== $batch_files && ! empty( $batch_files ) );
		unset( $batch_files );
		return $result;
	}
}
