<?php
/**
 * This file is related to syncing simple products.
 *
 * @package    ProductSync
 * @subpackage SyncProducts\Simple
 * @author     miniOrange <info@miniorange.com>
 * @link       https://miniorange.com
 */

namespace MOWCPS\Common\Services\ProductSync\SyncType\Simple;

use MOWCPS\Common\Constants\Constants;
use MOWCPS\Common\Handlers\SyncHandler\Abstract_Sync_Handler;
use MOWCPS\Common\Utils\Model_Utils;
use MOWCPS\Common\Utils\Sync_Utils;
use MOWCPS\Common\Models\Sync_Details_DAO;
use MOWCPS\Common\Services\Product_Sync\SyncProducts\Simple\MO_Simple_Product;
use MOWCPS\Common\Services\Product_Sync\SyncProducts\MO_Product;
use MOWCPS\Common\Models\Product_Sync_Audit_Model;
use MOWCPS\Common\Constants\Plugin_Filters;
use MOWCPS\Common\Services\Logging\Supplier_Logger;

/**
 * This will be used to handle sync of simple products.
 */
class Sync_Simple_Products extends Abstract_Sync_Handler {

	use MO_Product;

	/**
	 * Product data from API.
	 *
	 * @var array
	 */
	public $product_data;

	/**
	 * Initialize the properties.
	 *
	 * @param int $supplier_id   The supplier ID.
	 * @param int $schedule_id   The schedule ID.
	 * @param int $connection_id Connection ID for which the sync is initiated.
	 *
	 * @return void
	 */
	public function __construct( $supplier_id, $schedule_id, $connection_id ) {
		$this->connection_id = $connection_id;
		$this->supplier_id   = $supplier_id;
		$this->schedule_id   = $schedule_id;
	}

	/**
	 * Sync Simple products.
	 *
	 * @return string Final sync status.
	 */
	public function start_sync_process() {

		/**
		 * This filter position is to perform any operations on the products array before starting product sync.
		 *
		 * 2nd parameter in apply_filter should be event identifier.
		 *
		 * Additional args/details should be sent as an in 3rd parameter of apply filter.
		 * The filter should return the same structure as the 3rd parameter, so other filter potions are not affected by your add-on.
		 *
		 * $this->product_data_from_api Same as class doc.
		 */

		if ( has_filter( Plugin_Filters::FILTER_DATA_ALTERATION_FILTER ) ) {
			$returned_data      = apply_filters(
				Plugin_Filters::FILTER_DATA_ALTERATION_FILTER,
				array(
					'event_specifier' => Plugin_Filters::EVENT_SIMPLE_PRODUCTS_DATA_ARRAY_INITIAL,
					'products_array'  => $this->product_data,
				)
			);
			$this->product_data = $returned_data['products_array'];
		}
		$product_array_size = count( $this->product_data );

		Supplier_Logger::debug( $this->supplier_id, 'Starting to sync ' . $product_array_size . ' simple products...' );

		$product_type_handler = apply_filters( Plugin_Filters::FILTER_PRODUCT_TYPE_HANDLER, array() );
		if ( isset( $product_type_handler[ Constants::SIMPLE ] ) ) {
			$product_class = $product_type_handler[ Constants::SIMPLE ];
			// Verify the class exists and extends our abstract class.
			if ( class_exists( $product_class ) ) {
				$product_type_handler = new $product_class( $this->supplier_id, $this->schedule_id, $this->connection_id );
			}
		} else {
			$product_type_handler = new MO_Simple_Product( $this->supplier_id, $this->schedule_id, $this->connection_id );
		}
		$sync_analytics            = Sync_Details_DAO::get_instance()->get_batch_analytics();
		$supplier_sync_analytics   = Sync_Details_DAO::get_instance()->get_supplier_analytics( $this->supplier_id, $this->schedule_id );
		$connection_sync_analytics = Sync_Details_DAO::get_instance()->get_connection_analytics( $this->supplier_id, $this->schedule_id, $this->connection_id );
		$object_reuse_counter      = 0;

		for ( $i = 0; $i < $product_array_size; $i++ ) {
			$running_status = Product_Sync_Audit_Model::get_sync_running_status( $this->supplier_id, $this->schedule_id );
			if ( Constants::SYNC_RUNNING_STATUS_OFF !== $running_status ) {

				// Recreate product object periodically to prevent memory accumulation.
				if ( $object_reuse_counter >= 10 ) {
					unset( $product_type_handler );

					$product_type_handler = apply_filters( Plugin_Filters::FILTER_PRODUCT_TYPE_HANDLER, array() );
					if ( isset( $product_type_handler[ Constants::SIMPLE ] ) ) {
						$product_class = $product_type_handler[ Constants::SIMPLE ];
						if ( class_exists( $product_class ) ) {
							$product_type_handler = new $product_class( $this->supplier_id, $this->schedule_id, $this->connection_id );
						}
					} else {
						$product_type_handler = new MO_Simple_Product( $this->supplier_id, $this->schedule_id, $this->connection_id );
					}
					$object_reuse_counter = 0;
					Sync_Utils::trigger_garbage_collection();
				}
				$current_product_data = $this->product_data[ $i ];

				if ( has_filter( Plugin_Filters::FILTER_CURRENT_DATA_ALTERATION_FILTER ) ) {
					$returned_data = apply_filters(
						Plugin_Filters::FILTER_CURRENT_DATA_ALTERATION_FILTER,
						array(
							'event_specifier' => Plugin_Filters::FILTER_CURRENT_DATA_ALTERATION_FILTER,
							'product_data'    => $current_product_data,
						)
					);
					$current_product_data = $returned_data['product_data'];
				}

				unset( $this->product_data[ $i ] );
				$product_name       = isset( $current_product_data['name'] ) ? $current_product_data['name'] : 'Unknown Product';
				$product_sku        = isset( $current_product_data['sku'] ) ? $current_product_data['sku'] : 'No SKU';
				$product_identifier = $product_name . ' (SKU: ' . $product_sku . ')';

				Supplier_Logger::debug( $this->supplier_id, 'Processing product ' . ( $i + 1 ) . '/' . $product_array_size . ': ' . $product_identifier );

				$operation = $product_type_handler->determine_operation( $this->connection_id, $current_product_data, 'main' );
				$product_type_handler->set_fields( $current_product_data, $operation );
				$product_obj = $product_type_handler->save( $this->connection_id, $current_product_data, 'main' );
				++$object_reuse_counter;
				if ( is_array( $product_obj ) ) {
					$product_id = isset( $product_obj['id'] ) ? (int) $product_obj['id'] : 0;
				} else {
					$product_id = (int) $product_obj;
				}

				if ( $product_id > 0 ) {
					Supplier_Logger::debug( $this->supplier_id, 'Successfully synced: ' . $product_identifier . ' (WooCommerce ID: ' . $product_id . ')' );
					Sync_Utils::increment_success_counters( $sync_analytics, $supplier_sync_analytics, $connection_sync_analytics );

				} else {
					// Determine failure reason.
					$failure_reason = 'Unknown error';
					if ( is_string( $product_obj ) ) {
						$failure_reason = $product_obj;
					} elseif ( is_wp_error( $product_obj ) ) {
						$failure_reason = $product_obj->get_error_message();
					}

					Supplier_Logger::debug( $this->supplier_id, 'Failed to sync: ' . $product_identifier . ' - Reason: ' . $failure_reason );
					Sync_Utils::increment_failure_counters( $sync_analytics, $supplier_sync_analytics, $connection_sync_analytics );
				}
				Sync_Utils::increment_parsed_counters( $sync_analytics, $supplier_sync_analytics, $connection_sync_analytics );
				$last_row_count = $sync_analytics->additional_sync_data['last_row_count'] ?? 0;
				++$last_row_count;
				$sync_analytics->additional_sync_data['last_row_count'] = $last_row_count;
				Sync_Utils::save_analytics( $sync_analytics, $supplier_sync_analytics, $connection_sync_analytics );

				// Memory cleanup after processing each product.
				unset( $current_product_data );
				unset( $product_obj );
				if ( $i > 0 && $i % 10 === 0 ) {
					Sync_Utils::cleanup_memory();
					Sync_Utils::trigger_garbage_collection();
				}

				// Log progress every 10 products to avoid log spam.
				if ( ( $i + 1 ) % 10 === 0 || ( $i + 1 ) === $product_array_size ) {
					$processed      = $i + 1;
					$success_so_far = $sync_analytics->product_saved_success ?? 0;
					$failed_so_far  = $sync_analytics->product_saved_fail ?? 0;
					Supplier_Logger::debug( $this->supplier_id, 'Progress: ' . $processed . '/' . $product_array_size . ' products processed (' . $success_so_far . ' success, ' . $failed_so_far . ' failed)' );
				}
			} else {
				$status_result = Sync_Utils::handle_sync_status( $this->supplier_id, $this->schedule_id, $sync_analytics );
				if ( false !== $status_result ) {
					if ( Constants::SYNC_PAUSED === $status_result ) {
						Supplier_Logger::debug( $this->supplier_id, 'Sync paused by user at product ' . ( $i + 1 ) . '/' . $product_array_size );
					} elseif ( Constants::SYNC_ABORTED === $status_result ) {
						Supplier_Logger::debug( $this->supplier_id, 'Sync stopped by user at product ' . ( $i + 1 ) . '/' . $product_array_size );
					}
					return $status_result;
				}
			}
		}
		unset( $product_type_handler );
		unset( $this->product_data );
		Sync_Utils::cleanup_memory( true );

		// Log completion summary.
		$success_count   = $sync_analytics->product_saved_success ?? 0;
		$failed_count    = $sync_analytics->product_saved_fail ?? 0;
		$total_processed = $sync_analytics->total_product_parsed ?? 0;

		Supplier_Logger::debug( $this->supplier_id, 'Product sync completed! Summary:' );
		Supplier_Logger::debug( $this->supplier_id, 'Total processed: ' . $total_processed . ' products' );
		Supplier_Logger::debug( $this->supplier_id, 'Successfully synced: ' . $success_count . ' products' );
		if ( $failed_count > 0 ) {
			Supplier_Logger::debug( $this->supplier_id, 'Failed to sync: ' . $failed_count . ' products' );
		}
		return Sync_Utils::complete_sync( $sync_analytics );
	}
}
