<?php

namespace Simplyin\Simplyin_W_Plugin\Payments\Gateway\Status;

use Exception;
use Simplyin\Simplyin_W_Plugin\Lib\Remote\SimplyInApi\Api\PaymentsApi;
use Simplyin\Simplyin_W_Plugin\Lib\Remote\SimplyInApi\Configuration;
use Simplyin\Simplyin_W_Plugin\Lib\Remote\SimplyInApi\ObjectSerializer;
use Simplyin\Simplyin_W_Plugin\Lib\Session\Simplyin_Session;
use Simplyin\Simplyin_W_Plugin\Payments\Gateway\Model\Order_Data;
use Simplyin\Simplyin_W_Plugin\Payments\Gateway\Model\Payment_Type_Interface;
use Simplyin\Simplyin_W_Plugin\Payments\Remote\Sample_Response;

class Payment_Status {

	public const STATUS_PENDING = 'PENDING';

	public const STATUS_PAID = 'PAID';

	public const STATUS_CANCELED = 'CANCELED';

	public const STATUS_REJECTED = 'REJECTED';

	public const STATUS_REFUNDED = 'REFUNDED';


	private Order_Data $order_data;
	private Payment_Type_Interface $payment_type;

	/**
	 * @param Order_Data $order_data
	 */
	public function __construct( Order_Data $order_data ) {
		$this->order_data   = $order_data;
		$this->payment_type = $this->order_data->get_selected_payment_type();
	}

	private function refresh() {
		$this->payment_type = $this->order_data->get_selected_payment_type();

	}

	/**
	 * @throws Exception
	 */
	public function get_payment_status(): string {
		$paymentStatus = $this->payment_type->get_payment_status();

		return $paymentStatus ?? self::STATUS_PENDING;
	}

	/**
	 * @throws Exception
	 */
	public function get_payment_status_remote(): string {
		$paymentStatus = $this->payment_type->get_payment_status();

		simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
			sprintf( "[get_payment_status_remote] %s",
				wp_json_encode( [
					'paymentStatus' => is_null( $paymentStatus ) ? 'null' : $paymentStatus,
					'orderId'       => $this->order_data->get_order()->get_id(),
				] ),
			),
			'getPaymentStatus' );

		if ( ! $paymentStatus || $paymentStatus === self::STATUS_PENDING ) {
			$paymentStatusFromRemote = $this->get_payment_status_from_remote( $this->payment_type->get_payment_uuid() );
			if ( $paymentStatusFromRemote ) {
				if ( $paymentStatusFromRemote !== (string) $paymentStatus ) {
					$this->update_payment_status( $paymentStatusFromRemote );

					try {
						$mapped_wc_order_status = $this->map_wc_status( $paymentStatusFromRemote );
						$note                   = "Simply.IN webhook status received: $paymentStatusFromRemote. Mapped to Woocommerce status: $mapped_wc_order_status";
						$this->order_data->update_order_status( $mapped_wc_order_status,
							$note );
					} catch ( Exception $e ) {
						simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
							sprintf( "[map_wc_status unknown status from remote %s]",
								wp_json_encode( [
									'status'  => $paymentStatusFromRemote,
									'orderId' => $this->order_data->get_order()
									                              ->get_id(),
								] ),
							),
							'getPaymentStatus' );

						return $paymentStatus;
					}


					simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
						sprintf( "[update_payment_status] %s",
							wp_json_encode( [
								'paymentStatus' => $paymentStatusFromRemote,
								'orderId'       => $this->order_data->get_order()
								                                    ->get_id(),
							] ),
						),
						'getPaymentStatus' );
				}

				return $paymentStatusFromRemote;
			}
		}


		return $paymentStatus ?? self::STATUS_PENDING;
	}


	public function update_payment_status( string $new_payment_status ) {

		if ( ! in_array( $new_payment_status,
			$this->get_simplyin_payment_status_allowable_values() ) ) {
			throw new \Exception( esc_html( "Unknown status: $new_payment_status" ) );
		}

		$this->refresh();

		$current_payment_status = $this->get_payment_status();

		if ( $current_payment_status === self::STATUS_PAID ) {
			throw new \Exception( esc_html( "Current status is: $current_payment_status. Can't change to: $new_payment_status" ) );
		}

		$this->payment_type->set_payment_status( $new_payment_status );
		$this->order_data->update_selected_payment_method_type( $this->payment_type );

		simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
			sprintf( "[Payment_Status] [update_payment_status] %s",
				wp_json_encode( [
					'old' => $current_payment_status,
					'new' => $new_payment_status,

				] ),
			),
			'payments' );
	}


	public function map_wc_status( string $simplyin_status ): string {
		$map = [
			self::STATUS_PENDING  => 'wc-on-hold',
			self::STATUS_PAID     => 'wc-processing',
			self::STATUS_CANCELED => 'wc-failed',
			self::STATUS_REJECTED => 'wc-failed',
			self::STATUS_REFUNDED => 'wc-refunded',
		];

		if ( ! isset( $map[ $simplyin_status ] ) ) {
			throw new \Exception( esc_html( "Unknown status: $simplyin_status" ) );
		}

		return $map[ $simplyin_status ];
	}


	public function get_simplyin_payment_status_allowable_values() {
		return [
			self::STATUS_PENDING,
			self::STATUS_PAID,
			self::STATUS_CANCELED,
			self::STATUS_REJECTED,
			self::STATUS_REFUNDED,
		];
	}

	private function get_payment_status_from_remote( string $id = null
	): ?string {
		$simplyin_config  = simplyin()->get_simplyin_config();
		$simplyin_api_url = $simplyin_config['backendSimplyIn'];

		$config = new Configuration();

		$simplyin_auth_token = ( new Simplyin_Session() )->get( 'simplyin_auth_token' );

		if ( ! empty( $simplyin_auth_token ) ) {
			$config->setApiKey( 'api_token', $simplyin_auth_token );
		}

		$simplyin_api_key = get_option( 'simplyin_api_key' );
		$config->setApiKey( 'X-Auth-Merchant-Api-Key',
			$simplyin_api_key );


		$config->setHost( $simplyin_api_url );

		$raw = null;
		$api = new PaymentsApi( null, $config );
		try {
			$error     = '';
			$raw       = $api->paymentsGetPaymentStatus( $id );
			$to_return = $raw->getStatus();

		} catch ( Exception $e ) {
			$error     = $e->getMessage();
			$to_return = null;

		} finally {
			simplyin()->get_simplyin_logger()->log_if_wpdebug_on(
				sprintf( "[get_payment_status_from_remote] %s",
					wp_json_encode( [
						'simplyin_auth_token'   => $simplyin_auth_token,
						'simplyin_api_key'      => $simplyin_api_key,
						'payment id'            => $id,
						'status returned'       => $to_return,
						'error returned'        => $error,
						'raw response returned' => $raw,
					] ),
				),
				'getPaymentStatus' );
		}


		return $to_return;
	}

}
