<?php
/**
 * A class to expire (cancel) a payment.
 *
 * @since 3.0.0
 */

declare( strict_types=1 );
namespace FeData\FastEvents\Hooks\Actions;

defined( 'ABSPATH' ) || exit;

use FeData\FastEvents\Helpers\EventsHelper;
use FeData\FastEvents\Logging\LoggerFactory;
use FeData\FastEvents\Payment\PaymentFactory;

/**
 * A class to expire (cancel) a payment.
 */
final class PaymentExpireAction {

	/**
	 * PaymentExpireAction constructor.
	 *
	 * @since 3.0.0
	 *
	 * @param LoggerFactory  $logger        Logger.
	 * @param PaymentFactory $payment       Payment factory.
	 * @param EventsHelper   $events_helper Event helper functions.
	 */
	public function __construct(
		private readonly LoggerFactory $logger,
		private readonly PaymentFactory $payment,
		private readonly EventsHelper $events_helper
	) {}

	/**
	 * Cancel (expire) the payment if it is still open.
	 *
	 * @since 3.0.0
	 * @param int $order_id Order identifier.
	 */
	public function expire_payment( int $order_id ): void {
		global $wpdb;

		// Look up the id and check if the payment is still open.
		$order_table = $wpdb->prefix . 'fe_event_orders';
		$event_table = $wpdb->prefix . 'fe_events';
		// phpcs:disable
		$result = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT $order_table.id, $order_table.uid, $order_table.payment_status, $order_table.input_fields, $order_table.event_id, " .
				"$order_table.created_at, $order_table.payment_id, $event_table.test_payments_needed, $event_table.saas_user_id " .
				"FROM $order_table " .
				"INNER JOIN $event_table ON $event_table.id = $order_table.event_id " .
				"WHERE $order_table.id = %d",
				$order_id
			)
		);
		// phpcs:enable

		// Does the key exist?
		if ( null === $result ) {
			$this->logger->warning(
				'Cannot find the order with id "' . $order_id . '" in the database.',
				array(
					'type'     => 'Payment canceled',
					'order_id' => $order_id,
				)
			);
			return;
		}

		// Cancel the payment if it is still open.
		$json = json_decode( $result->input_fields, true );
		if ( 'open' === $result->payment_status ) {

			// Delete tickets and set the status to 'expired' and save the expiry time in the metadata of the input_fields.
			$date = current_time( 'mysql' );
			$ids  = empty( $json['orders'] ) ? array( $order_id ) : array_map( 'intval', $json['orders'] );
			$wpdb->query(
				"UPDATE {$wpdb->prefix}fe_event_orders SET payment_status ='expired', " .
				"input_fields = JSON_INSERT(input_fields, '$.metadata', JSON_OBJECT(), '$.metadata.expired_at', '$date' )" . // phpcs:ignore
				'WHERE id IN (' . implode( ',', $ids ) . ')' // phpcs:ignore
			);
			$this->events_helper->fast_events_delete_tickets( $json['events'], $json['orders'] );

			// Inform the payment provider to cancel the payment.
			$this->payment->cancel_payment( $result->payment_id, (int) $result->saas_user_id, (bool) $result->test_payments_needed );

			// Log the error for each order.
			foreach ( array_map( 'intval', $json['orders'] ) as $key => $order_id ) {
				$this->logger->warning(
					esc_html__( 'The order has expired because the user did not pay on time', 'fast-events' ),
					array(
						'type'     => 'Order expire timer',
						'order_id' => (int) $order_id,
						'event_id' => (int) $json['events'][ $key ],
					)
				);
			}
		}
	}
}
