<?php

namespace Simplyin\Simplyin_W_Plugin\Sync;

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

use Simplyin\Simplyin_W_Plugin\Lib\Remote\Sin_Core_Api\Simplyin_Api_Legacy_Client;
use Simplyin\Simplyin_W_Plugin\Payments\Gateway\Webhook_Context;
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' ] );
		// Path B (priority 10, async): queues update_order_status to background process
		// for orders with SimplyInOrderId only. See also Path A in simplyin.php (priority 1).
		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 ( '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 status change
	 */
	public function change_status( $order_id, $old_status, $new_status ) {
		if ( Webhook_Context::is_processing( (int) $order_id ) ) {
			return;
		}

		$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() {
		$page_size = 500;
		$offset    = 0;

		do {
			$user_ids = get_users( [
				'role__in' => [ 'customer', 'subscriber' ],
				'fields'   => 'ID',
				'number'   => $page_size,
				'offset'   => $offset,
			] );

			if ( empty( $user_ids ) ) {
				break;
			}

			foreach ( $user_ids as $user_id ) {
				$this->process_all->push_to_queue( [
					'action'  => 'check_user',
					'user_id' => (int) $user_id,
				] );
			}

			$this->process_all->save();
			$offset += count( $user_ids );

		} while ( count( $user_ids ) === $page_size );

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

	/**
	 * Get all users and sync with SimplyIn
	 */
	public function simplyin_initial_user_sync() {
		$page_size = 500;
		$offset    = 0;

		do {
			$users = get_users( [
				'role__in' => [ 'customer', 'subscriber' ],
				'fields'   => [ 'ID', 'user_email' ],
				'number'   => $page_size,
				'offset'   => $offset,
			] );

			if ( empty( $users ) ) {
				break;
			}

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

			$this->process_all->save();
			$offset += count( $users );

		} while ( count( $users ) === $page_size );

		$this->process_all->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' ) ) ) {
			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" );

			simplyinActivate();
		}

		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 ) {
				$current_value = get_option( 'simplyin_register_by_default' );
				// Always backup before overwriting; use sentinel when option was never set.
				$backup_value = ( false === $current_value ) ? '__not_set__' : (string) $current_value;
				simplyin()->update_option( 'SimplyInRegisterByDefaultStateOld', $backup_value, 'sync' );
				simplyin()->update_option( 'SimplyInRegisterByDefaultDisabled', true, 'sync' );
				simplyin()->update_option( 'simplyin_register_by_default', 'off', 'sync' );
			} else {
				$was_disabled_by_api = '1' === (string) get_option( 'SimplyInRegisterByDefaultDisabled' );
				simplyin()->update_option( 'SimplyInRegisterByDefaultDisabled', false, 'sync' );

				if ( $was_disabled_by_api ) {
					$backup = get_option( 'SimplyInRegisterByDefaultStateOld' );

					if ( false === $backup || '__not_set__' === $backup ) {
						// Option was never set before API disabled — apply sensible default.
						simplyin()->update_option( 'simplyin_register_by_default', 'on', 'sync' );
					} else {
						// Restore merchant's previous setting; normalize legacy values.
						if ( '1' === $backup ) {
							$backup = 'on'; // Pre-5.5.29 slider format.
						} elseif ( '' === $backup ) {
							$backup = 'off'; // Normalize empty to explicit canonical value.
						}
						simplyin()->update_option( 'simplyin_register_by_default', $backup, 'sync' );
					}

					simplyin()->update_option( 'SimplyInRegisterByDefaultStateOld', '', '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_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" );
		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" );

		$page       = 1;
		$batch_size = 200;
		$total      = 0;

		do {
			$query     = new WC_Order_Query(
				[
					'limit'        => $batch_size,
					'paged'        => $page,
					'date_created' => '>=' . gmdate( "Y-m-d H:i:s", $lastSyncTimestamp ),
					'return'       => 'ids',
				]
			);
			$order_ids = $query->get_orders();

			foreach ( $order_ids as $order_id ) {
				$order = wc_get_order( $order_id );
				if ( ! $order ) {
					continue;
				}
				if ( 1 === (int) $order->get_meta( 'SimplyInOrderExported', true ) ) {
					continue;
				}
				$this->process_all->push_to_queue( [
					'action'   => 'create_order',
					'order_id' => $order_id,
				] );
				$order->update_meta_data( 'SimplyInOrderInQueue', 1 );
				$order->save_meta_data();
			}

			$total += count( $order_ids );
			$page++;
		} while ( count( $order_ids ) === $batch_size );

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

		$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;
	}

}
