<?php
/**
 * This file is for performing the sync analytics supplier specific functionality.
 *
 * @package    ProductSync
 * @subpackage SyncAnalytics
 * @author     miniOrange <info@miniorange.com>
 * @link       https://miniorange.com
 */

namespace MOWCPS\Common\Handlers\SyncAnalytics;

use MOWCPS\Common\Constants\Constants;
use MOWCPS\Common\Models\Product_Sync_Audit_Model;
/**
 * Sync analytics.
 */
class Sync_Analytics {
	/**
	 * Connection name of the analytics.
	 *
	 * @var string
	 */
	public $supplier_id;

	/**
	 * Connection ID of the analytics.
	 *
	 * @var int
	 */
	public $connection_id = null;

	/**
	 * Schedule ID of the analytics.
	 *
	 * @var int
	 */
	public $schedule_id = null;

	/**
	 *  To check new sync for given connection can be initiated.
	 *
	 * @var boolean
	 */
	public $initiate_sync = true;

	/**
	 * Sync process start time as unix timestamp.
	 *
	 * @var int
	 */
	public $sync_start_time = 0;

	/**
	 * Sync process end time as unix timestamp.
	 *
	 * @var int
	 */
	public $sync_end_time = 0;

	/**
	 * Sync status code.
	 *
	 * @var string
	 */
	public $sync_status_code = '';

	/**
	 * Current sync status message.
	 *
	 * @var string
	 */
	public $sync_status_message = '';

	/**
	 * Number of products iterated in the sync process.
	 *
	 * @var integer
	 */
	public $total_success_products_parsed = 0;

	/**
	 * Number of products iterated in the sync process.
	 *
	 * @var integer
	 */
	public $total_product_parsed = 0;

	/**
	 * Count of product's whose save operation were successful.
	 *
	 * @var integer
	 */
	public $product_saved_success = 0;

	/**
	 * Count of product's whose save operation were failed.
	 *
	 * @var integer
	 */
	public $product_saved_fail = 0;

	/**
	 * Count of variable variations whose save operation succeeded (stored as variation_success_parsed).
	 *
	 * @var int
	 */
	public $variation_success_parsed = 0;

	/**
	 * Count of simple products that do not come from the API.
	 *
	 * @var integer
	 */
	public $discarded_simple_products = 0;

	/**
	 * Count of variations product's that do not come from api.
	 *
	 * @var integer
	 */
	public $discarded_variation_products = 0;

	/**
	 * Additional details related to sync.
	 *
	 * List:
	 *  ~ current_variation_number.
	 *
	 * @var array
	 */
	public $additional_sync_data = array(
		'current_product_child_count' => 0,
	);

	/**
	 * Current product child count.
	 *
	 * @var int
	 */
	public $current_product_child_count = 0;

	/**
	 * Sub-type of product analytics.
	 *
	 * ENUM(PRO\Constants::VENDOR_AVAILABLE_PRODUCTS, Constants::VENDOR_UNAVAILABLE_PRODUCTS, 'complete_connection') DEFAULT Constants::VENDOR_AVAILABLE_PRODUCTS.
	 *
	 * @var string
	 */
	public $analytics_type = Constants::VENDOR_AVAILABLE_PRODUCTS;

	/**
	 * Batch number for the analytics.
	 *
	 * @var int|null
	 */
	public $batch_number = null;

	/**
	 * Database status field (mapped from sync_status_code)
	 *
	 * @var string
	 */
	public $status = '';

	/**
	 * Database status_message field (mapped from sync_status_message)
	 *
	 * @var string
	 */
	public $status_message = '';

	/**
	 * Database end_time field (mapped from sync_end_time)
	 *
	 * @var int
	 */
	public $end_time = 0;

	/**
	 * Database total_parsed field (mapped from total_product_parsed)
	 *
	 * @var int
	 */
	public $total_parsed = 0;

	/**
	 * Database parsed_success field (mapped from product_saved_success)
	 *
	 * @var int
	 */
	public $parsed_success = 0;

	/**
	 * Database parsed_failed field (mapped from product_saved_fail)
	 *
	 * @var int
	 */
	public $parsed_failed = 0;

	/**
	 * Database additional_data field (mapped from additional_sync_data)
	 *
	 * @var array
	 */
	public $additional_data = array();

	/**
	 * Constructor.
	 *
	 * @param string   $supplier_id   Analytics ID of the supplier.
	 * @param int      $schedule_id   Schedule ID for the analytics. Default null.
	 * @param int      $connection_id Connection ID for the analytics. Default null.
	 * @param int|null $batch_number Batch number for the analytics. Default null.
	 */
	public function __construct( $supplier_id, $schedule_id = null, $connection_id = null, $batch_number = null ) {
		$this->supplier_id   = $supplier_id;
		$this->connection_id = $connection_id;
		$this->schedule_id   = $schedule_id;
		$this->batch_number  = $batch_number;
	}

	/**
	 * Initiate the analytics process.
	 *
	 * @param string $sync_type The type of sync being initiated.
	 * @return void
	 */
	public function initiate_analytics( $sync_type ) {
		$this->setup_analytics( $sync_type );
	}

	/**
	 * Setup analytics for the plugin.
	 *
	 * @return void
	 */
	public function setup_analytics( $sync_type ) {
		Product_Sync_Audit_Model::delete( $this->supplier_id, $this->schedule_id, $this->connection_id );
		Product_Sync_Audit_Model::create(
			array(
				'supplier_id'   => $this->supplier_id,
				'schedule_id'   => $this->schedule_id,
				'connection_id' => $this->connection_id,
				'sync_type'     => $sync_type,
				'batch_number'  => $this->batch_number,
			)
		);
		$this->set_values();
	}

	/**
	 * Set analytics values
	 *
	 * @return void
	 */
	public function set_values() {
		$analytics_data = Product_Sync_Audit_Model::get_sync_audit( $this->supplier_id, $this->schedule_id, $this->connection_id, $this->batch_number );

		if ( ! $analytics_data ) {
			Product_Sync_Audit_Model::create(
				array(
					'supplier_id'   => $this->supplier_id,
					'schedule_id'   => $this->schedule_id,
					'connection_id' => $this->connection_id,
					'batch_number'  => $this->batch_number,
				)
			);

			$analytics_data = Product_Sync_Audit_Model::get_sync_audit( $this->supplier_id, $this->schedule_id, $this->connection_id, $this->batch_number );
		}

		// Extract properties from the row object.
		$this->set_analytics_object( $analytics_data );
	}

	/**
	 * Get the number of products parsed in the current batch.
	 *
	 * @return int The number of products parsed in the current batch.
	 */
	public static function get_parsed_product_count( $supplier_id, $schedule_id, $connection_id, $batch_number ) {
		$analytics_data = Product_Sync_Audit_Model::get_sync_audit( $supplier_id, $schedule_id, $connection_id, $batch_number );
		if ( empty( $analytics_data ) ) {
			return 0;
		}
		return (int) ( $analytics_data->total_product_parsed ?? 0 );
	}

	/**
	 * Set analytics object values from the given object.
	 *
	 * @param object $analytics_object Analytics object.
	 * @return void
	 */
	public function set_analytics_object( $analytics_object ) {
		if ( empty( $analytics_object ) || ! is_object( $analytics_object ) ) {
			return;
		}

		$this->initiate_sync               = json_decode( $analytics_object->initiate_sync, true );
		$this->sync_start_time             = $analytics_object->start_time ?? $this->sync_start_time;
		$this->sync_end_time               = $analytics_object->end_time ?? $this->sync_end_time;
		$this->sync_status_code            = $analytics_object->status ?? $this->sync_status_code;
		$this->sync_status_message         = $analytics_object->status_message ?? $this->sync_status_message;
		$this->total_product_parsed        = $analytics_object->total_parsed ?? $this->total_product_parsed;
		$this->product_saved_success       = $analytics_object->parsed_success ?? $this->product_saved_success;
		$this->product_saved_fail          = $analytics_object->parsed_failed ?? $this->product_saved_fail;
		$this->variation_success_parsed    = $analytics_object->variation_success_parsed ?? $this->variation_success_parsed;
		$this->current_product_child_count = $analytics_object->current_child_product_count ?? $this->current_product_child_count;
		$this->additional_sync_data        = $analytics_object->additional_data ? json_decode( $analytics_object->additional_data, true ) : $this->additional_sync_data;
		$this->analytics_type              = $analytics_object->sync_type ?? $this->analytics_type;
		$this->batch_number                = $analytics_object->batch_number ?? $this->batch_number;
	}

	/**
	 * Save's analytics object in wp_options table.
	 */
	public function save() {
		Product_Sync_Audit_Model::update( $this );
	}

	/**
	 * Update's analytics object to fetch real-time sync analytics object for a connection.
	 *
	 * @return void
	 */
	public function update_analytics() {
		$latest_analytics_object = Product_Sync_Audit_Model::get_sync_audit( $this->supplier_id, $this->schedule_id, $this->connection_id );

		if ( isset( $latest_analytics_object[0] ) ) {
			$latest_analytics_object = $latest_analytics_object[0];
		} else {
			$this->setup_analytics();
			$latest_analytics_object = $this;
		}

		// Get analytics of all batches.
		$analytics_array = Product_Sync_Audit_Model::get_sync_audit( $this->supplier_id, $this->schedule_id, $this->connection_id, $this->batch_number, true );

		$total_variation_success = 0;
		if ( ! empty( $analytics_array ) ) {
			$sync_status_message      = '';
			$total_saved_success      = 0;
			$total_saved_fail         = 0;
			$total_parsed             = 0;
			$total_variation_success  = 0;
			$this->initiate_sync      = true;
			foreach ( $analytics_array as $analytics_object ) {
				$total_saved_success = $total_saved_success + $analytics_object->product_saved_success;
				$total_saved_fail    = $total_saved_fail + $analytics_object->product_saved_fail;
				$total_parsed        = $total_parsed + $analytics_object->total_product_parsed;
				$total_variation_success = $total_variation_success + $analytics_object->variation_success_parsed;

				if ( $sync_status_message !== $analytics_object->sync_status_message ) {
					$sync_status_message = '';
				}

				$this->initiate_sync = $this->initiate_sync && $analytics_object->initiate_sync;
			}
		} else {
			$this->initiate_sync = $latest_analytics_object->initiate_sync;
		}

		$this->sync_start_time          = $latest_analytics_object->sync_start_time ?? '0';
		$this->total_product_parsed     = empty( $total_parsed ) ? $latest_analytics_object->total_product_parsed : $total_parsed;
		$this->product_saved_success    = empty( $total_saved_success ) ? $latest_analytics_object->product_saved_success : $total_saved_success;
		$this->product_saved_fail       = empty( $total_saved_fail ) ? $latest_analytics_object->product_saved_fail : $total_saved_fail;
		$this->variation_success_parsed = empty( $total_variation_success ) ? (int) ( $latest_analytics_object->variation_success_parsed ?? $this->variation_success_parsed ) : $total_variation_success;
		$this->additional_sync_data     = json_decode( $latest_analytics_object->additional_sync_data, true );
		$this->sync_status_message      = empty( $sync_status_message ) ? $latest_analytics_object->sync_status_message : $sync_status_message;
		$this->save();
	}
}
