<?php
namespace KnitPayUPI\Gateways\UpiQR\Mobikwik;

use KnitPayUPI\Gateways\UpiQR\KnitPayUPIGateway;
use Pronamic\WordPress\Http\Facades\Http;
use Pronamic\WordPress\Pay\Payments\FailureReason;
use Pronamic\WordPress\Pay\Payments\Payment;
use Pronamic\WordPress\Pay\Payments\PaymentStatus;
use Pronamic\WordPress\Pay\Payments\PaymentStatus as Core_Statuses;
use Exception;


/**
 * Title: MobiKwik Gateway
 * Copyright: 2020-2026 Knit Pay
 *
 * @author Knit Pay
 * @version 1.6.0.0
 * @since 1.6.0.0
 */
class Gateway extends KnitPayUPIGateway {
	private $client;

	/**
	 * Constructs and initializes an MobiKwik gateway
	 *
	 * @param Config $config
	 *            Config.
	 */
	public function __construct( Config $config ) {     
		parent::__construct( $config );

		$this->show_manual_confirmation = true;
		if ( 'auto' !== $config->payment_status_mode ) {
			$this->payment_expiry_seconds = 600;
			$this->enable_polling         = false;
		}

		$this->client = new Client( $config );
	}
	
	/**
	 * Start.
	 *
	 * @see KnitPayUPIGateway::start()
	 *
	 * @param Payment $payment
	 *            Payment.
	 */
	public function start( Payment $payment ) {
		parent::start( $payment );

		// Check connection.
		$connection_data = get_post_meta( $this->config->config_id, '_pronamic_gateway_upi_qr_mobikwik_connection_data', true );
		$connection_data = json_decode( $connection_data, true );
		$this->client->get_wallet_history( $connection_data );

		// get the unique amount in case of auto mode.
		if ( 'auto' === $this->config->payment_status_mode ) {
			$this->make_amount_unique( $payment );
		}

		$result = $this->get_gateway_data( $payment );

		$payment->set_meta( 'mobikwik_data', $result->data->mobikwik_data );
		$payment->set_meta( 'kpp_charge_id', $result->id );
	}

	/**
	 * Update status of the specified payment.
	 *
	 * @param Payment $payment
	 *            Payment.
	 */
	public function update_status( Payment $payment ) {
		parent::update_status( $payment );

		if ( ! empty( $_POST['knit_pay_utr'] ) ) {
			$knit_pay_utr = sanitize_text_field( $_POST['knit_pay_utr'] );

			$payment->set_transaction_id( $knit_pay_utr );

			$old_payment = get_pronamic_payment_by_transaction_id( $knit_pay_utr );

			if ( null !== $old_payment ) {
				$failure_reason = new FailureReason();
				$failure_reason->set_message( 'Trying to use same UTR twice. UTR: ' . $knit_pay_utr );
				$failure_reason->set_code( 'FRAUD' );
				$payment->set_failure_reason( $failure_reason );
				
				$payment->set_status( Core_Statuses::FAILURE );
				return;
			}
		}

		$mobikwik_data = json_decode( $payment->get_meta( 'mobikwik_data' ), true );
		$transactions  = $this->client->get_wallet_history( $mobikwik_data );

		$found_transaction = (object) [];
		$expected_amount   = floatval( $payment->get_total_amount()->number_format( null, '.', '' ) );

		foreach ( $transactions as $transaction ) {
			// Check if payment occurred during expected time.
			if ( $transaction->date > $mobikwik_data['end_date'] ) {
				// check next payment.
				continue;
			} elseif ( $transaction->date < $mobikwik_data['start_date'] ) {
				// stop searching payments if we don't find payments within expected timeframe.
				break;
			} elseif ( ! $transaction->showCreditedTo || 'success' !== $transaction->status ) {
				// Skip if it's a debit transaction or fail transaction.
				continue;
			}

			if ( 'auto' === $this->config->payment_status_mode && floatval( $transaction->amount ) === $expected_amount ) {
				// check if this transaction already used.
				$old_payment = get_pronamic_payment_by_transaction_id( $transaction->rrn );

				// if not already used, use this transaction.
				if ( null !== $old_payment ) {
					continue;
				}

				/*
				* This transaction occured during the expected timeframe, amount of the transaction matches
				* and the transaction has not been used before. So, we are assuming this this the transaction we are looking for.
				*/
				$payment->set_transaction_id( $transaction->rrn );
				$payment->set_status( Core_Statuses::SUCCESS );
				$payment->add_note( '<strong>MobiKwik Response:</strong><br><pre>' . print_r( $transaction, true ) . '</pre><br>' );

				// This amount is paid and now can be allocated to other customer.
				$current_amount = $payment->get_total_amount()->get_minor_units()->to_int();
				delete_transient( 'knit_pay_upi_' . $this->config->config_id . '_' . $current_amount );
				return;
			} elseif ( $payment->get_transaction_id() === $transaction->rrn ) {
				$found_transaction = $transaction;
			}
		}

		if ( property_exists( $found_transaction, 'status' ) && 'success' === $found_transaction->status ) {
			if ( floatval( $found_transaction->amount ) !== $expected_amount ) {
				$payment->set_status( Core_Statuses::FAILURE );
				return;
			}

			$payment->set_status( Core_Statuses::SUCCESS );
			$payment->add_note( '<strong>MobiKwik Response:</strong><br><pre>' . print_r( $found_transaction, true ) . '</pre><br>' );
		} else {
			$this->expire_old_upi_payment( $payment );
		}
	}
}
