<?php

namespace SugarCalendarBookings\Payments;

use Exception;

/**
 * Class PaymentTransactionGenerator.
 *
 * @since 1.0.0
 */
class PaymentTracking {

	/**
	 * Max retries.
	 *
	 * @since 1.0.0
	 *
	 * @var int
	 */
	private const MAX_RETRIES = 5;

	/**
	 * Get a tracking ID.
	 *
	 * @since 1.0.0
	 *
	 * @param string $prefix Tracking ID prefix.
	 *
	 * @return string
	 * @throws Exception If a unique tracking ID can't be generated.
	 */
	public function get_id( $prefix ) {

		$attempts = 0;

		while ( $attempts < self::MAX_RETRIES ) {
			$tracking_id = $this->generate_tracking_id( $prefix );

			$payment = PaymentModel::query()
				->where( 'tracking_id', '=', $tracking_id, '%s' )
				->first();

			// Check if ID already exists in database.
			if ( $payment === null ) {
				return $tracking_id;
			}

			++$attempts;

			// TODO: maybe log collision.

			// Brief sleep to change timestamp on retry.
			if ( $attempts < self::MAX_RETRIES ) {
				usleep( 1000 );
			}
		}

		// TODO: maybe add fallback method.

		throw new Exception( esc_html__( 'Error generating transaction ID', 'sugar-calendar-bookings-scheduling-appointments-lite' ) );
	}

	/**
	 * Generate a unique transaction ID.
	 *
	 * @since 1.0.0
	 *
	 * @param string $prefix Transaction ID prefix.
	 *
	 * @return string
	 */
	private function generate_tracking_id( $prefix ) {

		$timestamp = str_replace( '.', '', (string) microtime( true ) );
		$random    = wp_rand( 1000, 9999 );

		return "$prefix-$timestamp-$random";
	}
}
