<?php

namespace MOWCPS\Common\Controllers;

use MOWCPS\Common\Handlers\SyncHandler\Backup_Sync_Handler;
use MOWCPS\Common\Handlers\SyncHandler\Batch_Sync_Handler;
use MOWCPS\Common\Handlers\SupplierHandler\Supplier_Handler;
use MOWCPS\Common\Constants\Constants;
use MOWCPS\Common\Factories\Vendor_Hook_Factory;
use MOWCPS\Common\Models\Supplier_Model;
use MOWCPS\Common\Models\Sync_Details_DAO;
use MOWCPS\Common\Utils\Model_Utils;
use MOWCPS\Common\Models\Product_Sync_Audit_Model;
use MOWCPS\Common\Handlers\SyncAnalytics\Sync_Analytics;
use MOWCPS\Common\Utils\Utils;
use MOWCPS\Common\Utils\Sync_Utils;
use MOWCPS\Common\Services\Logging\Supplier_Logger;
use MOWCPS\Common\Hooks\Promostandards;
use MOWCPS\Common\Constants\Plugin_Filters;
/**
 * Cron Controller Class.
 *
 * Handles starting supplier, batch, and backup sync processes via cron jobs.
 *
 * @package    ProductSync
 * @subpackage SupplierHandler
 * @author     miniOrange <info@miniorange.com>
 * @link       https://miniorange.com
 */
class Cron_Controller {

	/**
	 * Start the supplier sync process.
	 *
	 * This method triggers the manual supplier sync for a specific supplier ID.
	 *
	 * @param array $cron_args Arguments passed from the cron event.
	 *
	 * @return void
	 */
	public static function start_supplier_sync( $cron_args = array() ) {
		$supplier_id = $cron_args['supplier_id'];
		Supplier_Logger::debug( $supplier_id, 'Scheduled sync started automatically' );

		$supplier_app_type = Supplier_Model::get_by_id( $supplier_id, 'app_type' );
		Supplier_Logger::debug( $supplier_id, 'Connecting to ' . ucfirst( str_replace( '_', ' ', $supplier_app_type['app_type'] ) ) . ' supplier' );
		Sync_Details_DAO::get_instance()->set_supplier_app_type( $supplier_app_type['app_type'] );
		Sync_Details_DAO::get_instance()->set_supplier_id( $supplier_id );

		if ( ! empty( $cron_args['schedule_id'] ) ) {
			$schedule_id = $cron_args['schedule_id'];
			Sync_Details_DAO::get_instance()->set_schedule_id( $schedule_id );
		} else {
			$schedule_id = null;
		}

		$current_default_app_handler = self::instantiate_vendor_hook_class( $supplier_app_type['app_type'] );

		$sync_end_status = new Supplier_Handler( $supplier_id, $schedule_id );
		Supplier_Logger::debug( $supplier_id, 'Preparing to sync products from your supplier...' );
		$sync_end_status->start_supplier_sync();
	}

	/**
	 * Start the batch sync process.
	 *
	 * This method triggers the batch sync using the provided cron arguments.
	 *
	 * @param array $cron_args Arguments passed from the cron event.
	 *
	 * @return void
	 */
	public static function start_batch_sync( $cron_args = array() ) {
		Supplier_Logger::debug( $cron_args['supplier_id'], 'batch sync started time stamp: ' . time() );
		$supplier = Supplier_Model::get_by_id( $cron_args['supplier_id'] );
		Sync_Details_DAO::get_instance()->set_supplier_app_type( $cron_args['vendor_name'] );
		Sync_Details_DAO::get_instance()->set_supplier_id( $cron_args['supplier_id'] );
		$current_default_app_handler = self::instantiate_vendor_hook_class( $supplier['app_type'] );
		$batch_sync_handler          = new Batch_Sync_Handler( $cron_args );
		$batch_sync_handler->start_batch_sync();
	}

	/**
	 * Start the backup sync process.
	 *
	 * This method triggers the backup sync using the provided cron arguments.
	 *
	 * @param array $cron_args Arguments passed from the cron event.
	 *
	 * @return void
	 */
	public static function start_backup_sync( $cron_args = array() ) {
		if ( has_filter( Plugin_Filters::FILTER_MANULLAY_CREATE_BACKUP_CRON ) ) {
			apply_filters(
				Plugin_Filters::FILTER_MANULLAY_CREATE_BACKUP_CRON,
				array(
					'event_specifier' => Plugin_Filters::EVENT_UPDATE_MANUAL_BACKUP_CRON,
					'supplier_id'     => $cron_args['supplier_id'],
					'connection_id'   => $cron_args['connection_id'],
					'additional_data'   => array(
						'updated_cron_arguments' => $cron_args,
					),
				)
			);
		}
		
		$current_default_app_handler = self::instantiate_vendor_hook_class( $cron_args['vendor_name'] );
		$backup_sync_handler         = new Backup_Sync_Handler( $cron_args );
		$backup_sync_handler->start_backup_sync();
	}

	/**
	 * This method stops the sync process for a given supplier and schedule ID.
	 *
	 * @param array $cron_args Arguments passed from the cron event, including 'supplier_id' and 'schedule_id'.
	 *
	 * @return void
	 */
	public static function stop_sync( $cron_args = array() ) {
		$supplier_id = isset( $cron_args['supplier_id'] ) ? $cron_args['supplier_id'] : null;
		$schedule_id = isset( $cron_args['schedule_id'] ) ? $cron_args['schedule_id'] : null;

		Supplier_Logger::debug( $supplier_id, 'Sync abort/stop requested by user' );

		$sync_in_process = Product_Sync_Audit_Model::get_sync_running_status( $supplier_id, $schedule_id );

		$supplier_app_type = Supplier_Model::get_by_id( $cron_args['supplier_id'], 'app_type' );
		self::instantiate_vendor_hook_class( $supplier_app_type['app_type'] );

		if ( has_action( 'mowcps_stop_sync' ) ) {
			do_action( 'mowcps_stop_sync', $cron_args );
		}

		if ( Constants::SYNC_RUNNING_STATUS_ON === $sync_in_process || Constants::PAUSED_SYNC_RUNNING_STATUS === Model_Utils::get_option( 'mowcps_' . $supplier_id . '_' . $schedule_id . '_sync_running_status' ) ) {
			Supplier_Logger::debug( $supplier_id, 'Aborting sync process - terminating all operations' );
			Product_Sync_Audit_Model::update_sync_running_status( $supplier_id, $schedule_id, Constants::SYNC_RUNNING_STATUS_OFF );
			Model_Utils::update_option( 'mowcps_message', 'Sync connection ' . $supplier_id . ' process Aborted.' );
			Model_Utils::update_option( 'mowcps_message_flag', 2 );
			Model_Utils::update_option( 'mowcps_' . $supplier_id . '_' . $schedule_id . '_sync_running_status', Constants::STOPPED_SYNC_RUNNING_STATUS );
			$sync_analytics = new Sync_Analytics( $supplier_id, $schedule_id );
			$sync_analytics->set_analytics_object( Product_Sync_Audit_Model::get_sync_audit( $supplier_id, $schedule_id ) );
			$sync_analytics->sync_status_message = Constants::SYNC_ABORTED;
			$sync_analytics->sync_status_code    = Constants::SYNC_ABORTED;
			$sync_analytics->sync_end_time       = time();
			$sync_analytics->save();
			Sync_Utils::cleanup_all_batch_files_for_supplier( $supplier_id );
			Supplier_Logger::debug( $supplier_id, 'Sync successfully aborted - all processes terminated' );
			exit();
		} else {
			Supplier_Logger::debug( $supplier_id, 'Cannot abort sync - no active or paused sync process found' );
			Model_Utils::update_option( 'mowcps_message', 'Sync connection ' . $supplier_id . ' has no process to abort.' );
			Model_Utils::update_option( 'mowcps_message_flag', 1 );
			exit();
		}
	}


	/**
	 * Pause sync.
	 *
	 * @param array $cron_args Arguments passed from the cron event, including 'supplier_id' and 'schedule_id'.
	 *
	 * @return void
	 */
	public static function pause_sync( $cron_args = array() ) {
		$supplier_id = isset( $cron_args['supplier_id'] ) ? $cron_args['supplier_id'] : null;
		$schedule_id = isset( $cron_args['schedule_id'] ) ? $cron_args['schedule_id'] : null;

		Supplier_Logger::debug( $supplier_id, 'Sync pause requested by user' );

		$sync_in_process = Product_Sync_Audit_Model::get_sync_running_status( $supplier_id, $schedule_id );
		if ( Constants::SYNC_RUNNING_STATUS_ON === $sync_in_process ) {
			Supplier_Logger::debug( $supplier_id, 'Pausing active sync process...' );
			Utils::store_paused_sync_cron_event( $supplier_id, $schedule_id );
			Product_Sync_Audit_Model::update_sync_running_status( $supplier_id, $schedule_id, Constants::SYNC_RUNNING_STATUS_OFF );
			Model_Utils::update_option( 'mowcps_' . $supplier_id . '_' . $schedule_id . '_sync_running_status', Constants::PAUSED_SYNC_RUNNING_STATUS );
			Model_Utils::update_option( 'mowcps_message', 'Sync connection ' . $supplier_id . ' process paused.' );
			Supplier_Logger::debug( $supplier_id, 'Sync successfully paused - can be resumed later' );
			Model_Utils::update_option( 'mowcps_message_flag', 2 );
			$sync_analytics = new Sync_Analytics( $supplier_id, $schedule_id );
			$sync_analytics->set_analytics_object( Product_Sync_Audit_Model::get_sync_audit( $supplier_id, $schedule_id ) );
			$sync_analytics->sync_status_message = Constants::SYNC_PAUSED;
			$sync_analytics->sync_status_code    = Constants::SYNC_PAUSED;
			$sync_analytics->sync_end_time       = time();
			$sync_analytics->save();
			exit();
		} else {
			Supplier_Logger::debug( $supplier_id, 'Cannot pause sync - no active sync process found' );
			Model_Utils::update_option( 'mowcps_message', 'Sync connection ' . $supplier_id . ' has no process to pause.' );
			Model_Utils::update_option( 'mowcps_message_flag', 1 );
			exit();
		}
	}

	/**
	 * Resume sync.
	 *
	 * @param array $cron_args Arguments passed from the cron event, including 'supplier_id' and 'schedule_id'.
	 *
	 * @return void
	 */
	public static function resume_sync( $cron_args = array() ) {
		$supplier_id = isset( $cron_args['supplier_id'] ) ? $cron_args['supplier_id'] : null;
		$schedule_id = isset( $cron_args['schedule_id'] ) ? $cron_args['schedule_id'] : null;

		Supplier_Logger::debug( $supplier_id, 'Sync resume requested by user' );

		$sync_in_process = Product_Sync_Audit_Model::get_sync_running_status( $supplier_id, $schedule_id );
		if ( Constants::SYNC_RUNNING_STATUS_OFF === $sync_in_process ) {
			Model_Utils::update_option( 'mowcps_message', 'Sync connection ' . $supplier_id . ' process resumed.' );
			Model_Utils::update_option( 'mowcps_message_flag', 1 );
			Product_Sync_Audit_Model::update_sync_running_status( $supplier_id, $schedule_id, Constants::SYNC_RUNNING_STATUS_ON );
			Model_Utils::update_option( 'mowcps_' . $supplier_id . '_' . $schedule_id . '_sync_running_status', Constants::RESUMED_SYNC_RUNNING_STATUS );

			$paused_cron_args = Model_Utils::get_option( 'mowcps_paused_cron_' . $supplier_id . '_' . $schedule_id );
			if ( empty( $paused_cron_args ) ) {
				Supplier_Logger::debug( $supplier_id, 'Cannot resume sync - no paused sync data found' );
				Model_Utils::update_option( 'mowcps_message', 'No paused sync found for supplier ' . $supplier_id . '.' );
				Model_Utils::update_option( 'mowcps_message_flag', 2 );
				exit();
			}

			Supplier_Logger::debug( $supplier_id, 'Resuming paused sync process...' );
			$next_cron = Utils::get_next_cron_frequency();
			\wp_schedule_event( time(), 'mowcps_' . $next_cron . '_sec', 'mowcps_product_sync_backup_cron', array( $paused_cron_args ) );
			$sync_analytics = new Sync_Analytics( $supplier_id, $schedule_id );
			$sync_analytics->set_analytics_object( Product_Sync_Audit_Model::get_sync_audit( $supplier_id, $schedule_id ) );
			$sync_analytics->sync_status_message = 'Sync Resumed';
			$sync_analytics->sync_status_code    = 'Sync Resumed';
			$sync_analytics->sync_start_time     = time();
			$sync_analytics->sync_end_time       = 0;
			$sync_analytics->save();

			Supplier_Logger::debug( $supplier_id, 'Sync successfully resumed from previous pause point' );

			exit();
		} else {
			Supplier_Logger::debug( $supplier_id, 'Cannot resume sync - sync is already running' );
			Model_Utils::update_option( 'mowcps_message', 'Sync connection ' . $supplier_id . ' is already in process.' );
			Model_Utils::update_option( 'mowcps_message_flag', 2 );
			exit();
		}
	}

	/**
	 * Instantiate vendor hook class using Strategy pattern.
	 *
	 * Uses Vendor_Hook_Factory to create vendor hook instances.
	 * Follows Open-Closed Principle - new vendors can be added via factory registration
	 * without modifying this method.
	 *
	 * @param string $vendor_name Vendor name for which we need to perform operations.
	 *
	 * @return \MOWCPS\Common\Interfaces\Hookable_Interface|null Vendor hook instance or null if not found.
	 */
	public static function instantiate_vendor_hook_class( $vendor_name ) {
		return Vendor_Hook_Factory::create( $vendor_name );
	}
}
