<?php
/**
 * Sync Data Model Class
 *
 * @package ShopExplorer\Models
 * @since 1.0.0
 */

namespace SHOPEXPLORER\Models;

use SHOPEXPLORER\Exceptions\ShopExplorerException;

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

/**
 * Sync Data Model class
 *
 * Represents synchronization operations and status tracking
 *
 * @since 1.0.0
 */
class SHOPEX_SyncDataModel {

	/**
	 * Sync ID
	 *
	 * @var int
	 */
	public $sync_id;

	/**
	 * Entity type (order, product, vendor)
	 *
	 * @var string
	 */
	public $entity_type;

	/**
	 * Entity ID
	 *
	 * @var int
	 */
	public $entity_id;

	/**
	 * Sync operation (create, update, delete)
	 *
	 * @var string
	 */
	public $operation;

	/**
	 * Sync direction (to_sheets, from_sheets, bidirectional)
	 *
	 * @var string
	 */
	public $direction;

	/**
	 * Sync status
	 *
	 * @var string
	 */
	public $status;

	/**
	 * Source data
	 *
	 * @var array
	 */
	public $source_data;

	/**
	 * Target data
	 *
	 * @var array
	 */
	public $target_data;

	/**
	 * Error message
	 *
	 * @var string|null
	 */
	public $error_message;

	/**
	 * Retry count
	 *
	 * @var int
	 */
	public $retry_count;

	/**
	 * Max retries
	 *
	 * @var int
	 */
	public $max_retries;

	/**
	 * Priority level
	 *
	 * @var int
	 */
	public $priority;

	/**
	 * Vendor ID (for multivendor)
	 *
	 * @var int|null
	 */
	public $vendor_id;

	/**
	 * Created timestamp
	 *
	 * @var string
	 */
	public $created_at;

	/**
	 * Updated timestamp
	 *
	 * @var string
	 */
	public $updated_at;

	/**
	 * Scheduled timestamp
	 *
	 * @var string|null
	 */
	public $scheduled_at;

	/**
	 * Completed timestamp
	 *
	 * @var string|null
	 */
	public $completed_at;

	/**
	 * Valid entity types
	 *
	 * @var array
	 */
	private static $valid_entity_types = [
		'order',
		'product',
		'vendor',
		'customer',
	];

	/**
	 * Valid operations
	 *
	 * @var array
	 */
	private static $valid_operations = [
		'create',
		'update',
		'delete',
		'sync',
	];

	/**
	 * Valid directions
	 *
	 * @var array
	 */
	private static $valid_directions = [
		'to_sheets',
		'from_sheets',
		'bidirectional',
	];

	/**
	 * Valid statuses
	 *
	 * @var array
	 */
	private static $valid_statuses = [
		'pending',
		'processing',
		'completed',
		'failed',
		'cancelled',
		'retrying',
	];

	/**
	 * Priority levels
	 *
	 * @var array
	 */
	private static $priority_levels = [
		'low' => 1,
		'normal' => 5,
		'high' => 10,
		'urgent' => 15,
	];

	/**
	 * Constructor
	 *
	 * @param array $data Sync data
	 */
	public function __construct( $data = [] ) {
		$this->populate( $data );
	}

	/**
	 * Populate model with data
	 *
	 * @param array $data Sync data
	 */
	public function populate( $data ) {
		$this->sync_id = isset( $data['id'] ) ? (int) $data['id'] : 0;
		$this->entity_type = isset( $data['entity_type'] ) ? sanitize_text_field( $data['entity_type'] ) : '';
		$this->entity_id = isset( $data['entity_id'] ) ? (int) $data['entity_id'] : 0;
		$this->operation = isset( $data['operation'] ) ? sanitize_text_field( $data['operation'] ) : 'sync';
		$this->direction = isset( $data['direction'] ) ? sanitize_text_field( $data['direction'] ) : 'bidirectional';
		$this->status = isset( $data['status'] ) ? sanitize_text_field( $data['status'] ) : 'pending';
		$this->source_data = isset( $data['source_data'] ) ? (array) $data['source_data'] : [];
		$this->target_data = isset( $data['target_data'] ) ? (array) $data['target_data'] : [];
		$this->error_message = isset( $data['error_message'] ) ? sanitize_textarea_field( $data['error_message'] ) : null;
		$this->retry_count = isset( $data['retry_count'] ) ? (int) $data['retry_count'] : 0;
		$this->max_retries = isset( $data['max_retries'] ) ? (int) $data['max_retries'] : 3;
		$this->priority = isset( $data['priority'] ) ? (int) $data['priority'] : self::$priority_levels['normal'];
		$this->vendor_id = isset( $data['vendor_id'] ) ? (int) $data['vendor_id'] : null;
		$this->created_at = isset( $data['created_at'] ) ? sanitize_text_field( $data['created_at'] ) : current_time( 'mysql' );
		$this->updated_at = isset( $data['updated_at'] ) ? sanitize_text_field( $data['updated_at'] ) : current_time( 'mysql' );
		$this->scheduled_at = isset( $data['scheduled_at'] ) ? sanitize_text_field( $data['scheduled_at'] ) : null;
		$this->completed_at = isset( $data['completed_at'] ) ? sanitize_text_field( $data['completed_at'] ) : null;
	}

	/**
	 * Validate sync data
	 *
	 * @return bool|array True if valid, array of errors if invalid
	 */
	public function validate() {
		$errors = [];

		// Validate entity type
		if ( ! in_array( $this->entity_type, self::$valid_entity_types, true ) ) {
			$errors[] = sprintf(
				/* translators: %s: is the product id */
				__( 'Invalid entity type: %s', 'shop-explorer' ),
				$this->entity_type
			);
		}

		// Validate entity ID
		if ( empty( $this->entity_id ) ) {
			$errors[] = __( 'Entity ID is required', 'shop-explorer' );
		}

		// Validate operation
		if ( ! in_array( $this->operation, self::$valid_operations, true ) ) {
			$errors[] = sprintf(
				/* translators: %s: is the product id */
				__( 'Invalid operation: %s', 'shop-explorer' ),
				$this->operation
			);
		}

		// Validate direction
		if ( ! in_array( $this->direction, self::$valid_directions, true ) ) {
			$errors[] = sprintf(
				/* translators: %s: is the product id */
				__( 'Invalid direction: %s', 'shop-explorer' ),
				$this->direction
			);
		}

		// Validate status
		if ( ! in_array( $this->status, self::$valid_statuses, true ) ) {
			$errors[] = sprintf(
				/* translators: %s: is the product id */
				__( 'Invalid status: %s', 'shop-explorer' ),
				$this->status
			);
		}

		// Validate priority
		if ( $this->priority < 1 || $this->priority > 20 ) {
			$errors[] = __( 'Priority must be between 1 and 20', 'shop-explorer' );
		}

		// Validate retry count
		if ( $this->retry_count < 0 ) {
			$errors[] = __( 'Retry count cannot be negative', 'shop-explorer' );
		}

		if ( $this->max_retries < 0 ) {
			$errors[] = __( 'Max retries cannot be negative', 'shop-explorer' );
		}

		return empty( $errors ) ? true : $errors;
	}

	/**
	 * Convert to array
	 *
	 * @return array
	 */
	public function to_array() {
		return [
			'sync_id' => $this->sync_id,
			'entity_type' => $this->entity_type,
			'entity_id' => $this->entity_id,
			'operation' => $this->operation,
			'direction' => $this->direction,
			'status' => $this->status,
			'source_data' => $this->source_data,
			'target_data' => $this->target_data,
			'error_message' => $this->error_message,
			'retry_count' => $this->retry_count,
			'max_retries' => $this->max_retries,
			'priority' => $this->priority,
			'vendor_id' => $this->vendor_id,
			'created_at' => $this->created_at,
			'updated_at' => $this->updated_at,
			'scheduled_at' => $this->scheduled_at,
			'completed_at' => $this->completed_at,
		];
	}

	/**
	 * Convert to JSON
	 *
	 * @return string
	 */
	public function to_json() {
		return wp_json_encode( $this->to_array() );
	}

	/**
	 * Create from database row
	 *
	 * @param array $row Database row data
	 * @return self
	 */
	public static function from_db_row( $row ) {
		$data = [
			'id' => $row['id'] ?? 0,
			'entity_type' => $row['entity_type'] ?? '',
			'entity_id' => $row['entity_id'] ?? 0,
			'operation' => $row['operation'] ?? 'sync',
			'direction' => $row['direction'] ?? 'bidirectional',
			'status' => $row['status'] ?? 'pending',
			'source_data' => isset( $row['source_data'] ) ? json_decode( $row['source_data'], true ) : [],
			'target_data' => isset( $row['target_data'] ) ? json_decode( $row['target_data'], true ) : [],
			'error_message' => $row['error_message'] ?? null,
			'retry_count' => $row['retry_count'] ?? 0,
			'max_retries' => $row['max_retries'] ?? 3,
			'priority' => $row['priority'] ?? self::$priority_levels['normal'],
			'vendor_id' => $row['vendor_id'] ?? null,
			'created_at' => $row['created_at'] ?? current_time( 'mysql' ),
			'updated_at' => $row['updated_at'] ?? current_time( 'mysql' ),
			'scheduled_at' => $row['scheduled_at'] ?? null,
			'completed_at' => $row['completed_at'] ?? null,
		];

		return new self( $data );
	}

	/**
	 * Mark as processing
	 *
	 * @return self
	 */
	public function mark_processing() {
		$this->status = 'processing';
		$this->updated_at = current_time( 'mysql' );

		return $this;
	}

	/**
	 * Mark as completed
	 *
	 * @param array $target_data Target data after sync
	 * @return self
	 */
	public function mark_completed( $target_data = [] ) {
		$this->status = 'completed';
		$this->target_data = $target_data;
		$this->completed_at = current_time( 'mysql' );
		$this->updated_at = current_time( 'mysql' );

		return $this;
	}

	/**
	 * Mark as failed
	 *
	 * @param string $error_message Error message
	 * @return self
	 */
	public function mark_failed( $error_message ) {
		$this->status = 'failed';
		$this->error_message = sanitize_textarea_field( $error_message );
		$this->updated_at = current_time( 'mysql' );

		return $this;
	}

	/**
	 * Increment retry count
	 *
	 * @return self
	 */
	public function increment_retry() {
		$this->retry_count++;
		$this->status = $this->retry_count >= $this->max_retries ? 'failed' : 'retrying';
		$this->updated_at = current_time( 'mysql' );

		return $this;
	}

	/**
	 * Schedule sync operation
	 *
	 * @param string $scheduled_time Scheduled time
	 * @return self
	 */
	public function schedule( $scheduled_time ) {
		$this->scheduled_at = sanitize_text_field( $scheduled_time );
		$this->status = 'pending';
		$this->updated_at = current_time( 'mysql' );

		return $this;
	}

	/**
	 * Cancel sync operation
	 *
	 * @return self
	 */
	public function cancel() {
		$this->status = 'cancelled';
		$this->updated_at = current_time( 'mysql' );

		return $this;
	}

	/**
	 * Check if sync can be retried
	 *
	 * @return bool
	 */
	public function can_retry() {
		return $this->retry_count < $this->max_retries &&
			   in_array( $this->status, [ 'failed', 'retrying' ], true );
	}

	/**
	 * Check if sync is pending
	 *
	 * @return bool
	 */
	public function is_pending() {
		return $this->status === 'pending';
	}

	/**
	 * Check if sync is processing
	 *
	 * @return bool
	 */
	public function is_processing() {
		return $this->status === 'processing';
	}

	/**
	 * Check if sync is completed
	 *
	 * @return bool
	 */
	public function is_completed() {
		return $this->status === 'completed';
	}

	/**
	 * Check if sync has failed
	 *
	 * @return bool
	 */
	public function has_failed() {
		return $this->status === 'failed';
	}

	/**
	 * Check if sync is cancelled
	 *
	 * @return bool
	 */
	public function is_cancelled() {
		return $this->status === 'cancelled';
	}

	/**
	 * Get execution time in seconds
	 *
	 * @return int|null
	 */
	public function get_execution_time() {
		if ( ! $this->completed_at || ! $this->created_at ) {
			return null;
		}

		$start = strtotime( $this->created_at );
		$end = strtotime( $this->completed_at );

		return $end - $start;
	}

	/**
	 * Get priority name
	 *
	 * @return string
	 */
	public function get_priority_name() {
		foreach ( self::$priority_levels as $name => $level ) {
			if ( $this->priority <= $level ) {
				return $name;
			}
		}

		return 'urgent';
	}

	/**
	 * Set priority by name
	 *
	 * @param string $priority_name Priority name
	 * @return self
	 */
	public function set_priority( $priority_name ) {
		if ( isset( self::$priority_levels[ $priority_name ] ) ) {
			$this->priority = self::$priority_levels[ $priority_name ];
			$this->updated_at = current_time( 'mysql' );
		}

		return $this;
	}

	/**
	 * Get valid entity types
	 *
	 * @return array
	 */
	public static function get_valid_entity_types() {
		return self::$valid_entity_types;
	}

	/**
	 * Get valid operations
	 *
	 * @return array
	 */
	public static function get_valid_operations() {
		return self::$valid_operations;
	}

	/**
	 * Get valid directions
	 *
	 * @return array
	 */
	public static function get_valid_directions() {
		return self::$valid_directions;
	}

	/**
	 * Get valid statuses
	 *
	 * @return array
	 */
	public static function get_valid_statuses() {
		return self::$valid_statuses;
	}

	/**
	 * Get priority levels
	 *
	 * @return array
	 */
	public static function get_priority_levels() {
		return self::$priority_levels;
	}

	/**
	 * Check if entity type is valid
	 *
	 * @param string $entity_type Entity type to check
	 * @return bool
	 */
	public static function is_valid_entity_type( $entity_type ) {
		return in_array( $entity_type, self::$valid_entity_types, true );
	}

	/**
	 * Check if operation is valid
	 *
	 * @param string $operation Operation to check
	 * @return bool
	 */
	public static function is_valid_operation( $operation ) {
		return in_array( $operation, self::$valid_operations, true );
	}

	/**
	 * Check if direction is valid
	 *
	 * @param string $direction Direction to check
	 * @return bool
	 */
	public static function is_valid_direction( $direction ) {
		return in_array( $direction, self::$valid_directions, true );
	}

	/**
	 * Check if status is valid
	 *
	 * @param string $status Status to check
	 * @return bool
	 */
	public static function is_valid_status( $status ) {
		return in_array( $status, self::$valid_statuses, true );
	}
}
