<?php

namespace Simplyin\Simplyin_W_Plugin\Sync;

use Simplyin\Simplyin_W_Plugin\Lib\Remote\Sin_Core_Api\Simplyin_Api_Legacy_Client;
use WC_Order;
use WC_Order_Query;
use WP_Async_Request;

/**
 * BI-directional interface between plugin and BE
 */
class Simplyin_Sync {

	private $plugin_name;
	private $version;


	/**
	 * @var SimplyIn_Background_Process
	 */
	protected $process_all;
	protected $simplyin_api;

	protected $logs = [];

	protected WP_Async_Request $process_single;


	public function __construct( $plugin_name, $version ) {

		add_action( 'plugins_loaded', [ $this, 'init' ] );
		add_action( 'init', [ $this, 'process_handler' ] );
		add_action( 'woocommerce_order_status_changed',
			[ $this, 'change_status' ],
			10,
			3 );
		add_filter( 'pre_update_option_simplyin_api_key',
			[ $this, 'force_update_api_key' ],
			10,
			2 );

		add_action( 'update_option_simplyin_api_key',
			[ $this, 'simplyin_update_merchand_settings' ],
			10,
			2 );
		add_action( 'add_option_simplyin_api_key',
			[ $this, 'simplyin_update_merchand_settings' ],
			10,
			2 );
		$this->plugin_name = $plugin_name;
		$this->version     = $version;
	}

	public function force_update_api_key( $new_value, $old_value ) {
		if ( $new_value === $old_value ) {
			$this->simplyin_update_merchand_settings( $old_value, $new_value );
		}


		return $new_value;
	}

	/**
	 * Init
	 */
	public function init() {
		$this->simplyin_api = new Simplyin_Api_Legacy_Client( $this->plugin_name,
			$this->version );

		$this->process_single = new SimplyIn_Background_Request();
		$this->process_single->setSimplyInApi( $this->simplyin_api );

		$this->process_all = new SimplyIn_Background_Process();
		$this->process_all->setSimplyInApi( $this->simplyin_api );
	}

	/**
	 * Process handler
	 */
	public function process_handler() {
		if ( ! isset( $_GET['process'], $_GET['_wpnonce'] ) ) {
			return;
		}

		if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ),
			'process' ) ) {
			return;
		}

		$process = sanitize_text_field( wp_unslash( $_GET['process'] ) );

		if ( 'single' === $process ) {
			//$this->handle_single();
		}

		if ( 'all' === $process ) {
			$this->handle_all();
		}

		if ( 'initial' === $process ) {
			$this->simplyin_initial_user_sync();
		}

		if ( 'clean' === $process ) {
			$this->clean_queue();
		}
	}

	protected function clean_queue() {
		//todo: verify
		if ( is_object( $this->process_all->get_data() ) ) {
			$this->process_all->get_data()->delete_all();
		}

	}

	/**
	 * Handle single request
	 */
	protected function handle_single() {
		//$this->process_single->data( array( 'name' => $name ) )->dispatch();
	}

	/**
	 * Handle status change
	 */
	public function change_status( $order_id, $old_status, $new_status ) {
		$order = $this->get_wc_order_instance( (int) $order_id );

		if ( ! $order ) {
			return;
		}

		$simplyin_order_id = $order->get_meta( 'SimplyInOrderId' );
		if ( $simplyin_order_id ) {
			$this->process_all->push_to_queue( [
				'action'            => 'update_order_status',
				'order_id'          => $order_id,
				'simplyin_order_id' => $simplyin_order_id,
				'status'            => $new_status,
				'old_status'        => $old_status,
				'order'             => $order,

			] );
		}
		$this->process_all->save()->dispatch();
	}

	private function get_wc_order_instance( int $order_id ): ?WC_Order {
		$order = wc_get_order( $order_id );

		if ( false === $order instanceof WC_Order ) {
			return null;
		}

		return $order;
	}

	/**
	 * Handle all requests
	 */
	protected function handle_all() {
		$users = get_users( [
			'role__in' => [ 'customer', 'subscriber' ],
			'fields'   => [ 'id' ],
		] );

		foreach ( $users as $user ) {
			$this->process_all->push_to_queue( [
				'action'  => 'check_user',
				'user_id' => $user->id,
			] );
		}
		$this->process_all->save()->dispatch();
	}

	/**
	 * Get all users and sync with SimplyIn
	 */
	public function simplyin_initial_user_sync() {
		$users = get_users( [
			'role__in' => [ 'customer', 'subscriber' ],
			'fields'   => [ 'user_email', 'id' ],
		] );

		foreach ( $users as $user ) {
			$this->process_all->push_to_queue( [
				'action'     => 'verify_user',
				'user_email' => $user->user_email,
				'user_id'    => $user->ID,
			] );
		}
		$this->process_all->save()->dispatch();
	}

	/**
	 * Handle all requests
	 */
	public function simplyin_update_users() {
		$users = get_users( [
			'role__in' => [ 'customer', 'subscriber' ],
			'fields'   => [ 'user_email', 'id' ],
		] );

		foreach ( $users as $user ) {
			$this->process_all->push_to_queue( [
				'action'     => 'verify_user',
				'user_email' => $user->user_email,
				'user_id'    => $user->ID,
			] );
		}
		$this->process_all->save()->dispatch();
	}

	public function get_api(): Simplyin_Api_Legacy_Client {
		if ( ! $this->simplyin_api ) {
			$this->simplyin_api = new Simplyin_Api_Legacy_Client( $this->plugin_name,
				$this->version );
		}

		return $this->simplyin_api;
	}

	/**
	 * when key is updated try to fetch merchand settings, fired when api key
	 * is updated
	 */
	public function simplyin_update_merchand_settings(
		$old_api_key,
		$new_api_key
	) {


		simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
			sprintf( "[SimplyInSync] [hook: update_option_simplyin_api_key]" ),
			"sync" );


		// check if API urls exist in settings, if not activate it
		if ( empty( get_option( 'SimplyIn_Backend_Url', true ) ) ) {
			simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
				sprintf( "[SimplyInSync] [hook: update_option_simplyin_api_key] [API urls don\'t exist in settings. Now activate it]" ),
				"sync" );

			simpylinActivate();
		}

		if ( empty( $new_api_key ) ) {
			$response = null;
			simplyin()->update_option( 'SimplyInSettingsSuccessMsg',
				0 );

			simplyin()->update_option( 'SimplyInSettingsErrorMsg',
				__( 'Enter API key.',
					'simplyin' ) );
			simplyin()->update_option( 'SimplyInApiConnection',
				0,
				'sync' );
			simplyin()->update_option( 'SimplyInApiConnectedLastTry',
				time(),
				'sync' );

			return;
		} else {
			$response = $this->get_api()->sendRequest( 'plugin/sync',
				'POST',
				self::get_plugin_info_to_sync_request(),
				[],
				$new_api_key );
		}

		if ( $response && isset( $response->transactionHistoryLengthDays ) ) { // this means API responsed correctly
			simplyin()->update_option( 'SimplyInSettingsErrorMsg',
				0 );

			simplyin()->update_option( 'SimplyInSettingsSuccessMsg',
				__( 'Connected with Simply.IN',
					'simplyin' ),
				null,
				true );

			simplyin()
				->get_simplyin_logger()
				->log_if_wpdebug_on( "Successfull connection", "settings" );
			simplyin()->update_option( 'SimplyInApiConnection',
				1,
				'sync' );
			simplyin()->update_option( 'SimplyInApiConnectionLastTry',
				time(),
				'sync' );
			simplyin()->update_option( 'SimplyInTransactionHistoryLengthDay',
				$response->transactionHistoryLengthDays,
				'sync' );
			simplyin()->update_option( 'SimplyInSwitchLastChange',
				$response->switchInfo->lastChange,
				'sync' );
			simplyin()->update_option( 'SimplyInLogisticsPartnersOrder',
				$response->logisticsPartnersOrder->order,
				'sync' );

			if ( ! $response->switchInfo->isChecked ) {
				simplyin()->update_option( 'SimplyInRegisterByDefaultDisabled',
					true,
					'sync' );
				simplyin()->update_option( 'simplyin_register_by_default',
					false,
					'sync' );
			} else {
				simplyin()->update_option( 'SimplyInRegisterByDefaultDisabled',
					false,
					'sync' );
			}

			if ( isset( $response->docsInfo ) && ! empty( $response->docsInfo ) && is_array( $response->docsInfo ) ) {
				foreach ( $response->docsInfo as $doc ) {
					if ( isset( $doc->key ) ) {
						simplyin()->update_option( 'SimplyInDoc_' . $doc->key,
							$doc->url,
							'sync' );
					}
				}
			}

		} else {
			simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
				sprintf( "[SimplyInSync] [hook: update_option_simplyin_api_key] [failed] [response: %s]",
					wp_json_encode( $response ) ),
				"sync" );

			simplyin()->update_option( 'SimplyInSettingsSuccessMsg',
				0 );

			simplyin()->update_option( 'SimplyInSettingsErrorMsg',
				__( 'Error connecting to Simply.IN - check the API key.',
					'simplyin' ),
				null,
				true );

			simplyin()->update_option( 'SimplyInApiConnection',
				0,
				'sync' );
			simplyin()->update_option( 'SimplyInApiConnectedLastTry',
				time(),
				'sync' );
		}
	}

	/**
	 * Synchronize everything
	 */
	public function sync() {
		if ( get_option( 'SimplyInApiConnection' ) ) {
			$this->sync_orders();
			$this->sync_shipping();
			$this->sync_merchand_settings();
		}
	}

	protected function sync_merchand_settings() {
		//SimplyinLogger::log( "Sync merchant settings", "sync" );

		$this->process_all->push_to_queue( [ 'action' => 'update_merchant_settings' ] );
		$this->process_all->save()->dispatch();
	}

	protected function sync_shipping() {
		simplyin()
			->get_simplyin_logger()
			->log_if_wpdebug_on( "Sync shipping started", "sync" );

		$this->process_all->push_to_queue( [ 'action' => 'update_shipping_methods' ] );
		$this->process_all->save()->dispatch();
	}

	/**
	 * Sync orders from last time.
	 */
	protected function sync_orders() {

		simplyin()
			->get_simplyin_logger()
			->log_if_wpdebug_on( "Sync orders started", "sync" );
		$lastSyncTimestamp = get_option( 'SimplyInLastSyncTimestamp' );
		if ( ! $lastSyncTimestamp || $lastSyncTimestamp <= 0 ) { // if never done, take it back from $transactionHistoryLengthDay days.
			$transactionHistoryLengthDay = get_option( 'SimplyInTransactionHistoryLengthDay',
				180 );
			simplyin()
				->get_simplyin_logger()
				->log_if_wpdebug_on( "History length: " . $transactionHistoryLengthDay,
					"settings" );
			$lastSyncTimestamp = time() - 60 * 60 * 24 * $transactionHistoryLengthDay;
		}

		simplyin()
			->get_simplyin_logger()
			->log_if_wpdebug_on( "Last Synchronisation Timestamp: " . $lastSyncTimestamp,
				"sync" );
		$query  = new WC_Order_Query(
			[
				'limit'      => - 1,
				'meta_query' => [
					'relation' => 'OR',
					[
						'key'     => 'SimplyInOrderExported',
						'value'   => '1',
						'compare' => '!=',
					],
					[
						'key'     => 'SimplyInOrderInQueue',
						'value'   => '1',
						'compare' => '!=',
					],
					[
						'key'     => 'SimplyInOrderExported',
						'compare' => 'NOT EXISTS',
					],
					[
						'key'     => 'SimplyInOrderInQueue',
						'compare' => 'NOT EXISTS',
					],
				],
				'date_query' => [
					[
						'after'     => gmdate( "Y-m-d H:i:s",
							$lastSyncTimestamp ),
						'inclusive' => true,
					],
				],
				'return'     => 'ids',
			]
		);
		$orders = $query->get_orders();


		simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
			sprintf( "[SimplyInSync] [sync_orders] [date_query after: %s]",
				wp_json_encode( gmdate( "Y-m-d H:i:s",
					$lastSyncTimestamp ) ) ),
			"sync" );

		simplyin()
			->get_simplyin_logger()
			->log_if_wpdebug_on( "Number of orders to sync: " . ( $orders ? sizeof( $orders ) : "none" ),
				"sync" );

		foreach ( $orders as $order_id ) {
			$this->process_all->push_to_queue( [
				'action'   => 'create_order',
				'order_id' => $order_id,
			] );
			$order = wc_get_order( $order_id );
			$order->update_meta_data( 'SimplyInOrderInQueue', 1 );
			$order->save_meta_data();
		}
		$this->process_all->save()->dispatch();
		update_option( "SimplyInLastSyncTimestamp", time() );
	}

	public static function get_plugin_info_to_sync_request(
		array $body_data = []
	): array {

		$body_data['pluginVersion'] = SimplyInGetPluginVersion();
		$body_data['platform']      = 'WooCommerce';
		$body_data['shopName']      = addslashes( sanitize_text_field( get_bloginfo( 'name' ) ) );

		return $body_data;
	}

}
