<?php
/**
 * Data Synchronization Engine Class
 *
 * @package ShopExplorer\Sync
 * @since 1.0.0
 */

namespace SHOPEXPLORER\Sync;

use SHOPEXPLORER\Models\SyncDataModel;
use SHOPEXPLORER\Database\DatabaseManager;
use SHOPEXPLORER\Exceptions\SyncException;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Data Synchronization Engine class
 *
 * Manages sync operations with queue management and conflict resolution
 *
 * @since 1.0.0
 */
class SHOPEX_DataSyncEngine {

	/**
	 * Database manager instance
	 *
	 * @var SHOPEX_DatabaseManager
	 */
	private $database_manager;

	/**
	 * Sync queue table name
	 *
	 * @var string
	 */
	private $queue_table;

	/**
	 * Sync log table name
	 *
	 * @var string
	 */
	private $log_table;

	/**
	 * Maximum batch size for processing
	 *
	 * @var int
	 */
	private $batch_size = 50;

	/**
	 * Maximum execution time per batch (seconds)
	 *
	 * @var int
	 */
	private $max_execution_time = 30;

	/**
	 * Constructor
	 */
	public function __construct() {
		global $wpdb;

		$this->database_manager = new SHOPEX_DatabaseManager();
		$this->queue_table = $wpdb->prefix . 'shopex_sync_queue';
		$this->log_table = $wpdb->prefix . 'shopex_sync_log';
	}

	/**
	 * Add sync operation to queue
	 *
	 * @param string $entity_type Entity type (order, product, vendor)
	 * @param int    $entity_id Entity ID
	 * @param string $operation Operation (create, update, delete, sync)
	 * @param string $direction Direction (to_sheets, from_sheets, bidirectional)
	 * @param array  $options Additional options
	 * @return int Queue ID
	 * @throws SyncException
	 */
	public function queue_sync( $entity_type, $entity_id, $operation = 'sync', $direction = 'bidirectional', $options = [] ) {
		try {
			$sync_data = new SHOPEX_SyncDataModel( [
				'entity_type' => $entity_type,
				'entity_id' => $entity_id,
				'operation' => $operation,
				'direction' => $direction,
				'priority' => $options['priority'] ?? 5,
				'vendor_id' => $options['vendor_id'] ?? null,
				'scheduled_at' => $options['scheduled_at'] ?? null,
				'max_retries' => $options['max_retries'] ?? 3,
			] );

			// Validate sync data
			$validation = $sync_data->validate();
			if ( $validation !== true ) {
								return false;

			}

			// Insert into queue
			global $wpdb;

			$result = $wpdb->insert(
				$this->queue_table,
				[
					'entity_type' => $sync_data->entity_type,
					'entity_id' => $sync_data->entity_id,
					'operation' => $sync_data->operation,
					'direction' => $sync_data->direction,
					'status' => $sync_data->status,
					'priority' => $sync_data->priority,
					'vendor_id' => $sync_data->vendor_id,
					'retry_count' => $sync_data->retry_count,
					'max_retries' => $sync_data->max_retries,
					'created_at' => $sync_data->created_at,
					'updated_at' => $sync_data->updated_at,
					'scheduled_at' => $sync_data->scheduled_at,
				],
				[
					'%s',
					'%d',
					'%s',
					'%s',
					'%s',
					'%d',
					'%d',
					'%d',
					'%d',
					'%s',
					'%s',
					'%s',
				]
			);

			if ( $result === false ) {
								return false;

			}

			return $wpdb->insert_id;

		} catch ( \Exception $e ) {
						return false;
		}
	}

	/**
	 * Process sync queue
	 *
	 * @param int $limit Maximum number of items to process
	 * @return array Processing results
	 */
	public function process_queue( $limit = null ) {
		$limit = $limit ?? $this->batch_size;
		$start_time = time();
		$results = [
			'processed' => 0,
			'successful' => 0,
			'failed' => 0,
			'skipped' => 0,
			'errors' => [],
		];

		try {
			// Get pending sync operations
			$sync_operations = $this->get_pending_sync_operations( $limit );

			foreach ( $sync_operations as $sync_data ) {
				// Check execution time limit
				if ( time() - $start_time >= $this->max_execution_time ) {
					break;
				}

				$results['processed']++;

				try {
					// Process the sync operation
					$success = $this->process_sync_operation( $sync_data );

					if ( $success ) {
						$results['successful']++;
					} else {
						$results['failed']++;
						$results['errors'][] = "Failed to process sync ID: {$sync_data->sync_id}";
					}
				} catch ( \Exception $e ) {
								return false;
				}
			}
		} catch ( \Exception $e ) {
						return false;
		}

		return $results;
	}

	/**
	 * Process single sync operation
	 *
	 * @param SyncDataModel $sync_data Sync data model
	 * @return bool
	 * @throws SyncException
	 */
	private function process_sync_operation( $sync_data ) {
		try {
			// Mark as processing
			$sync_data->mark_processing();
			$this->update_sync_operation( $sync_data );

			// Get entity data
			$entity_data = $this->get_entity_data( $sync_data->entity_type, $sync_data->entity_id );

			if ( ! $entity_data ) {
								return false;

			}

			// Perform sync based on direction
			$success = false;

			switch ( $sync_data->direction ) {
				case 'to_sheets':
					$success = $this->sync_to_sheets( $sync_data, $entity_data );
					break;

				case 'from_sheets':
					$success = $this->sync_from_sheets( $sync_data );
					break;

				case 'bidirectional':
					$success = $this->bidirectional_sync( $sync_data, $entity_data );
					break;

				default:
					return false;

			}

			if ( $success ) {
				$sync_data->mark_completed();
				$this->log_sync_operation( $sync_data, 'completed' );
			} else {
				$sync_data->mark_failed( 'Sync operation returned false' );
				$this->log_sync_operation( $sync_data, 'failed' );
			}

			$this->update_sync_operation( $sync_data );
			return $success;

		} catch ( \Exception $e ) {
						return false;
		}
	}

	/**
	 * Sync entity to external service (No longer available)
	 *
	 * @param SyncDataModel $sync_data Sync data
	 * @param mixed         $entity_data Entity data
	 * @return bool
	 */
	private function sync_to_sheets( $sync_data, $entity_data ) {
		// External sync functionality has been removed
		return false;
	}

	/**
	 * Sync entity from external service (No longer available)
	 *
	 * @param SyncDataModel $sync_data Sync data
	 * @return bool
	 */
	private function sync_from_sheets( $sync_data ) {
		// External sync functionality has been removed
		return false;
	}

	/**
	 * Bidirectional sync with conflict resolution (No longer available)
	 *
	 * @param SyncDataModel $sync_data Sync data
	 * @param mixed         $entity_data Entity data
	 * @return bool
	 */
	private function bidirectional_sync( $sync_data, $entity_data ) {
		// External sync functionality has been removed
		return false;
	}

	/**
	 * Get pending sync operations
	 *
	 * @param int $limit Limit
	 * @return array
	 */
	private function get_pending_sync_operations( $limit ) {
		global $wpdb;

		$query = $wpdb->prepare(
			"SELECT * FROM {$this->queue_table} 
			 WHERE status IN ('pending', 'retrying') 
			 AND (scheduled_at IS NULL OR scheduled_at <= %s)
			 ORDER BY priority DESC, created_at ASC 
			 LIMIT %d",
			current_time( 'mysql' ),
			$limit
		);

		$results = $wpdb->get_results( $query, ARRAY_A );
		$sync_operations = [];

		foreach ( $results as $row ) {
			$sync_operations[] = SyncDataModel::from_db_row( $row );
		}

		return $sync_operations;
	}

	/**
	 * Update sync operation in database
	 *
	 * @param SyncDataModel $sync_data Sync data
	 * @return bool
	 */
	private function update_sync_operation( $sync_data ) {
		global $wpdb;

		return $wpdb->update(
			$this->queue_table,
			[
				'status' => $sync_data->status,
				'error_message' => $sync_data->error_message,
				'retry_count' => $sync_data->retry_count,
				'updated_at' => $sync_data->updated_at,
				'completed_at' => $sync_data->completed_at,
			],
			[ 'id' => $sync_data->sync_id ],
			[ '%s', '%s', '%d', '%s', '%s' ],
			[ '%d' ]
		) !== false;
	}

	/**
	 * Get entity data
	 *
	 * @param string $entity_type Entity type
	 * @param int    $entity_id Entity ID
	 * @return mixed|null
	 */
	private function get_entity_data( $entity_type, $entity_id ) {
		switch ( $entity_type ) {
			case 'order':
				return $this->database_manager->get_order( $entity_id );

			case 'product':
				return $this->database_manager->get_product( $entity_id );

			default:
				return null;
		}
	}

	/**
	 * Update local entity
	 *
	 * @param string $entity_type Entity type
	 * @param mixed  $entity_data Entity data
	 * @return bool
	 */
	private function update_local_entity( $entity_type, $entity_data ) {
		switch ( $entity_type ) {
			case 'order':
				return $this->database_manager->update_order( $entity_data );

			case 'product':
				return $this->database_manager->update_product( $entity_data );

			default:
				return false;
		}
	}

	/**
	 * Get spreadsheet configuration
	 *
	 * @param int|null $vendor_id Vendor ID
	 * @return array|null
	 */
	private function get_spreadsheet_config( $vendor_id = null ) {
		if ( $vendor_id ) {
			// Get vendor-specific configuration
			$config = get_user_meta( $vendor_id, 'vendor_sheet_configurations', true );
		} else {
			// Get global configuration
			$config = get_option( 'shopex_sheets_config' );
		}

		return $config ?: null;
	}

	/**
	 * Handle sync conflicts
	 *
	 * @param array         $conflicts Conflicts array
	 * @param SyncDataModel $sync_data Sync data
	 */
	private function handle_sync_conflicts( $conflicts, $sync_data ) {
		// Log conflicts for manual resolution
		foreach ( $conflicts as $conflict ) {
			$this->log_sync_conflict( $conflict, $sync_data );
		}
	}

	/**
	 * Log sync operation
	 *
	 * @param SyncDataModel $sync_data Sync data
	 * @param string        $status Status
	 * @param string        $message Message
	 */
	private function log_sync_operation( $sync_data, $status, $message = '' ) {
		global $wpdb;

		$wpdb->insert(
			$this->log_table,
			[
				'sync_id' => $sync_data->sync_id,
				'entity_type' => $sync_data->entity_type,
				'entity_id' => $sync_data->entity_id,
				'operation' => $sync_data->operation,
				'direction' => $sync_data->direction,
				'status' => $status,
				'message' => $message,
				'vendor_id' => $sync_data->vendor_id,
				'created_at' => current_time( 'mysql' ),
			],
			[ '%d', '%s', '%d', '%s', '%s', '%s', '%s', '%d', '%s' ]
		);
	}

	/**
	 * Log sync conflict
	 *
	 * @param array         $conflict Conflict data
	 * @param SyncDataModel $sync_data Sync data
	 */
	private function log_sync_conflict( $conflict, $sync_data ) {
		global $wpdb;

		$wpdb->insert(
			$this->log_table,
			[
				'sync_id' => $sync_data->sync_id,
				'entity_type' => $sync_data->entity_type,
				'entity_id' => $conflict['id'],
				'operation' => 'conflict',
				'direction' => $sync_data->direction,
				'status' => 'conflict',
				'message' => $conflict['reason'],
				'vendor_id' => $sync_data->vendor_id,
				'created_at' => current_time( 'mysql' ),
			],
			[ '%d', '%s', '%d', '%s', '%s', '%s', '%s', '%d', '%s' ]
		);
	}

	/**
	 * Get sync statistics
	 *
	 * @param array $filters Filters
	 * @return array
	 */
	public function get_sync_statistics( $filters = [] ) {
		global $wpdb;

		$where_clauses = [ '1=1' ];
		$where_values = [];

		if ( ! empty( $filters['vendor_id'] ) ) {
			$where_clauses[] = 'vendor_id = %d';
			$where_values[] = $filters['vendor_id'];
		}

		if ( ! empty( $filters['entity_type'] ) ) {
			$where_clauses[] = 'entity_type = %s';
			$where_values[] = $filters['entity_type'];
		}

		if ( ! empty( $filters['date_from'] ) ) {
			$where_clauses[] = 'created_at >= %s';
			$where_values[] = $filters['date_from'];
		}

		if ( ! empty( $filters['date_to'] ) ) {
			$where_clauses[] = 'created_at <= %s';
			$where_values[] = $filters['date_to'];
		}

		if ( ! empty( $where_clauses ) ) {
			$where_clause = implode( ' AND ', $where_clauses );
			$query = $wpdb->prepare(
				"SELECT 
					status,
					COUNT(*) as count,
					entity_type
					FROM {$this->queue_table} 
					WHERE {$where_clause}
					GROUP BY status, entity_type",
				$where_values
			);
		} else {
			$query = "SELECT 
				status,
				COUNT(*) as count,
				entity_type
				FROM {$this->queue_table} 
				GROUP BY status, entity_type";
		}

		$results = $wpdb->get_results( $query, ARRAY_A );

		$statistics = [
			'total' => 0,
			'by_status' => [],
			'by_entity_type' => [],
		];

		foreach ( $results as $row ) {
			$statistics['total'] += $row['count'];
			$statistics['by_status'][ $row['status'] ] = ( $statistics['by_status'][ $row['status'] ] ?? 0 ) + $row['count'];
			$statistics['by_entity_type'][ $row['entity_type'] ] = ( $statistics['by_entity_type'][ $row['entity_type'] ] ?? 0 ) + $row['count'];
		}

		return $statistics;
	}

	/**
	 * Clear completed sync operations
	 *
	 * @param int $days_old Days old to clear
	 * @return int Number of cleared operations
	 */
	public function clear_completed_operations( $days_old = 7 ) {
		global $wpdb;

		$date_threshold = date( 'Y-m-d H:i:s', strtotime( "-{$days_old} days" ) );

		$result = $wpdb->query(
			$wpdb->prepare(
				"DELETE FROM {$this->queue_table} 
				 WHERE status = 'completed' 
				 AND completed_at < %s",
				$date_threshold
			)
		);

		return $result !== false ? $result : 0;
	}

	/**
	 * Set batch size
	 *
	 * @param int $size Batch size
	 */
	public function set_batch_size( $size ) {
		$this->batch_size = max( 1, (int) $size );
	}

	/**
	 * Set maximum execution time
	 *
	 * @param int $time Time in seconds
	 */
	public function set_max_execution_time( $time ) {
		$this->max_execution_time = max( 10, (int) $time );
	}
}
