<?php

namespace Simplyin\Simplyin_W_Plugin\Sync;

use Simplyin\Simplyin_W_Plugin\Dto\Order\Order_DTO_Factory;
use Simplyin\Simplyin_W_Plugin\Dto\Order\Order_Items_DTO;
use WC_Data_Store;
use WC_Order;
use WC_Shipping_Zone;
use WP_Background_Process;

class SimplyIn_Background_Process extends WP_Background_Process {

	/**
	 * @var string
	 */
	protected $action = 'simplyin_background_process';
	protected $simplyin_api;
	private ?array $update_merchant_setting_response = null;

	public function get_data() {
		return $this->data;
	}

	/**
	 * Push to queue
	 *
	 * @param mixed $data Data.
	 *
	 * @return $this
	 */
	public function push_to_queue( $data ) {
		$log_data = $data;
		if ( isset( $log_data['order'] ) ) {
			$log_data['order'] = 'hidden in debug log';
		}
		simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
			sprintf( "[SimplyIn_Background_Process] [push_to_queue]  [data: %s]",
				wp_json_encode( $log_data ) ),
			"sync" );

		$this->data[] = $data;

		return $this;
	}


	/**
	 * Task
	 *
	 * Override this method to perform any actions required on each
	 * queue item. Return the modified item for further processing
	 * in the next pass through. Or, return false to remove the
	 * item from the queue.
	 *
	 * @param mixed $item Queue item to iterate over
	 *
	 * @return mixed
	 */

	public function setSimplyInApi( $simplyInApi ) {
		$this->simplyin_api = $simplyInApi;
	}


	//TODO: TESTY
	protected function task( $item ) {
		if ( isset( $item['action'] ) ) {
			switch ( $item['action'] ) {
				case 'check_user':
					$this->checkUserExist( $item['user_email'],
						$item['user_id'] );
					break;
				case 'verify_user':
					$this->checkUserExist( $item['user_email'],
						$item['user_id'] );
					break;
				case 'export_order':
					$this->updateHistory( $item['user_id'] );
					break;
				case 'create_order':
					$this->createOrder( $item['order_id'] );
					break;
				case 'update_shipping_methods':
					$this->updateShippingMethods();
					break;
				case 'update_order_status':
					if ( false === $item['order'] instanceof WC_Order ) {
						return false;
					}
					$this->updateOrderStatus(
						$item['simplyin_order_id'],
						$item['order'],
						$item['status'],
						$item['old_status'] );

					break;
				case 'update_merchant_settings':
					$this->updateMerchantSetting();
					break;
			}
		}

		return false;
	}

	/**
	 * Complete
	 *
	 * Override if applicable, but ensure that the below actions are
	 * performed, or, call parent::complete().
	 */
	protected function complete() {
		parent::complete();
	}


	/**
	 * Update merchant settings: GDPR, register by default, history length
	 */

	public function updateMerchantSetting() {
		$response = $this->simplyin_api->sendRequest( 'plugin/sync',
			'POST',
			Simplyin_Sync::get_plugin_info_to_sync_request(),
			[] );


		if ( $response && isset( $response->transactionHistoryLengthDays ) ) { // this means API responsed correctly

			simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
				sprintf( "[SimplyIn_Background_Process] [updateMerchantSetting] [Updating merchant settings] [response: %s]",
					wp_json_encode( $response ) ),
				"sync" );

			simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
				sprintf( "[SimplyIn_Background_Process] [updateMerchantSetting] [Updating merchant settings] [lastChange: %s] [SimplyInSwitchLastChange: %s]",
					wp_json_encode( (int) $response->switchInfo->lastChange ),
					wp_json_encode( (int) get_option( 'SimplyInSwitchLastChange',
						true ) ) ),
				"sync" );

			if ( (int) $response->switchInfo->lastChange > (int) get_option( 'SimplyInSwitchLastChange',
					true ) ) {
				// only when isChecked is false or null, disable button in admin and switch of
				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' );
					}
				}
				simplyin()->update_option( 'SimplyInSwitchLastChange',
					$response->switchInfo->lastChange,
					'sync' );
			}
			simplyin()->update_option( 'SimplyInLogisticsPartnersOrder',
				$response->logisticsPartnersOrder->order,
				'sync' );
			if ( isset( $response->docsInfo ) && ! empty( $response->docsInfo ) && is_array( $response->docsInfo ) ) {
				$docs = [];
				foreach ( $response->docsInfo as $doc ) {
					if ( isset( $doc->key ) ) {
						$docs[ sanitize_key( $doc->key ) ] = $doc->url;
					}
				}
				simplyin()->update_option( 'SimplyInDocs',
					$docs,
					'sync' );

			}

		}
	}

	/**
	 * This method check user exist in SimplyIn and mark him
	 *
	 * @param string $user_email
	 * @param int|null $user_id
	 */
	protected function checkUserExist( $user_email, $user_id = null ) {
		$bodyData = [ "data" => [ hash( 'sha256', $user_email ) ] ];
		$response = $this->simplyin_api->sendRequest( 'users/verifyHashedEmailsExist',
			'POST',
			$bodyData );

		if ( ! is_object( $response ) || ! isset( $response->ok ) ) {
			return false;
		}

		if ( empty( $response->data ) || ! isset( $response->data[0] ) ) {
			if ( $user_id ) {
				update_user_meta( $user_id, 'SimplyInUserExist', 0 );
			}

			return false;
		} else {
			if ( $response->data[0]->email == hash( 'sha256', $user_email ) ) {
				if ( $user_id ) {
					update_user_meta( $user_id, 'SimplyInUserExist', 1 );
					update_user_meta( $user_id,
						'SimplyInUserHmacEmail',
						$response->data[0]->hmacEmail );
					update_user_meta( $user_id,
						'SimplyInUserStatus',
						$response->data[0]->status );
				}

				return true;
			} else {
				if ( $user_id ) {
					update_user_meta( $user_id, 'SimplyInUserExist', 0 );
				}

				return false;
			}
		}
	}

	protected function updateHistory( $user_id ) {

	}

	protected function updateOrderStatus(
		$simplyin_order_id,
		WC_Order $order,
		$status,
		$old_status
	) {
		simplyin()
			->get_simplyin_logger()
			->log_if_wpdebug_on( sprintf( "[SimplyIn_Background_Process] [updateOrderStatus] [Background task] %s",
				wp_json_encode( [
					'simplyin_order_id' => $simplyin_order_id,
					'order_id'          => $order->get_id(),
					'old status'        => $old_status,
					'new status'        => $status,
				] )

			),
				"sync" );

		simplyin()
			->get_api()
			->simplyInOnOrderUpdate(
				$old_status,
				$status,
				$order );

	}

	protected function updateShippingMethods() {
		$methods                = array_values( $this->get_all_shipping_methods() );
		$body_data['providers'] = $methods;
		$response               = $this->simplyin_api->sendRequest( 'merchants/setLogisticsProviders',
			'POST',
			$body_data );
	}

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

		if ( false === $order instanceof WC_Order ) {
			$type = 'bool';
			if ( $order instanceof \WC_Order_Refund ) {
				$type = 'WC_Order_Refund';
			}

			simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
				sprintf( "[SimplyIn_Background_Process] [createOrder] [get_wc_order_instance] [%s is not instance of WC_ORDER] [ignoring]",
					wp_json_encode( $type ) ),
				"sync" );

			return null;

		}

		return $order;
	}

	protected function createOrder( $order_id ) {
		$order = $this->get_wc_order_instance( (int) $order_id );

		if ( null === $order ) {
			return;
		}

		if ( 1 === (int) $order->get_meta( 'SimplyInOrderExported', true ) ) {
			$order->delete_meta_data( 'SimplyInOrderInQueue' );
			$order->save_meta_data();

			return;
		}

		$order->delete_meta_data( 'SimplyInOrderInQueue' );
		$order->save_meta_data();
		/**
		 * MISSING -> subtotal_amount
		 * MISSING -> discount_amount
		 * MISSING -> tax_amount
		 */
		$user_email = $order->get_billing_email();
		// if user in SimplyIn create order for him
		if ( $this->checkUserExist( $user_email ) ) {
			$plugin_version      = SimplyInGetPluginVersion();
			$woocommerce_version = get_option( 'woocommerce_version' );
			$payment_method_data = SimplyInGetPaymentMethodData( $order );
			$body_data           = Order_DTO_Factory::build_create_order_body_data_dto(
				$order,
				$payment_method_data,
				$plugin_version,
				$woocommerce_version,
				'',
				'',
				'',
				'',
				'',
				'',
				$user_email
			)->toArray();


			$response = $this->simplyin_api->sendRequest( 'checkout/createOrder',
				"POST",
				$body_data );
			if ( $response && isset( $response->createdOrder )
				&& SimplyIn_Api_Order_Response::created_order_payload_is_for_this_wc_order( $response->createdOrder,
					$order ) ) {
				$order->update_meta_data( 'SimplyInOrderId',
					$response->createdOrder->_id );
				$order->update_meta_data( 'SimplyInOrderExported', 1 );

				simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
					sprintf( "[SimplyIn_Background_Process] [createOrder] Sync order success. [orderId: %s]",
						wp_json_encode( $order_id ) ),
					"sync" );

			} elseif ( SimplyIn_Api_Order_Response::response_indicates_order_already_exists( $response ) ) {
				$order->update_meta_data( 'SimplyInOrderExported', 1 );

				simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
					sprintf( "[SimplyIn_Background_Process] [createOrder] [Failed]  [message: %s] [order_id: %s] [user_email: %s]",
						wp_json_encode( is_object( $response ) && isset( $response->message ) ? $response->message : null ),
						wp_json_encode( $order_id ),
						wp_json_encode( $user_email ),
					),
					"sync" );

			} else {
				simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
					sprintf( "[SimplyIn_Background_Process] [createOrder] [Failed]  [message: %s] [order_id: %s] [user_email: %s]",
						wp_json_encode( is_object( $response ) && isset( $response->message ) ? $response->message : null ),
						wp_json_encode( $order_id ),
						wp_json_encode( $user_email ),
					),
					"sync" );
			}
		} else {
			simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
				sprintf( "[SimplyIn_Background_Process] [createOrder] checkUserExist returns false. [email: %s] [orderId: %s]",
					wp_json_encode( $user_email ),
					wp_json_encode( $order_id ) ),
				"sync" );
		}

		$order->save_meta_data();
	}


	protected function get_all_shipping_methods() {
		$methods    = [];
		$methodsIds = [];
		$data_store = WC_Data_Store::load( 'shipping-zone' );
		$raw_zones  = $data_store->get_zones();
		foreach ( $raw_zones as $raw_zone ) {
			$zone                  = new WC_Shipping_Zone( $raw_zone );
			$zone_shipping_methods = $zone->get_shipping_methods();
			foreach ( $zone_shipping_methods as $index => $method ) {
				if ( $method->is_enabled() ) {
					$methodsIds[]                      = $method->get_rate_id();
					$methods[ $method->get_rate_id() ] = $method->get_method_title();
				}
			}
		}

		return $methods;
	}
}
