<?php

namespace SugarCalendarBookings\Payments\Gateways\Stripe;

use Exception;
use SugarCalendarBookings\BookingForm\BookingFormService;
use SugarCalendarBookings\Payments\PaymentModel;
use SugarCalendarBookings\Payments\PaymentService;
use SugarCalendarBookings\Payments\PaymentsHelpers;
use SugarCalendarBookings\Plugin;
use SugarCalendarBookings\Services\ServiceModel;
use SugarCalendarBookings\Support\Bootable;
use SugarCalendarBookings\Support\DataProcessing\InputProcessor;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class StripeProvider.
 *
 * @since 1.0.0
 */
class StripeProvider implements Bootable {

	/**
	 * Payment gateway.
	 *
	 * @since 1.0.0
	 *
	 * @var StripePaymentGateway
	 */
	private $gateway;

	/**
	 * Constructor.
	 *
	 * @since 1.0.0
	 *
	 * @param StripePaymentGateway $gateway Payment gateway.
	 */
	public function __construct( $gateway ) {

		$this->gateway = $gateway;
	}

	/**
	 * Register hooks.
	 *
	 * @since 1.0.0
	 */
	public function hooks() {

		add_filter(
			'sugar_calendar_bookings_booking_form_payment_gateways',
			[ $this, 'get_booking_form_gateway_data' ]
		);

		add_filter(
			'sugar_calendar_bookings_booking_form_service_payment_gateways',
			[ $this, 'get_booking_form_service_gateway_data' ],
			10,
			2
		);

		add_filter(
			'sugar_calendar_bookings_booking_form_data',
			[ $this, 'get_booking_form_data' ]
		);

		add_action( 'wp_print_footer_scripts', [ $this, 'print_footer_scripts' ] );
	}

	/**
	 * Get booking form payment gateway data.
	 *
	 * @since 1.0.0
	 *
	 * @param array $payment_gateways Payment gateways data.
	 *
	 * @return array
	 */
	public function get_booking_form_gateway_data( $payment_gateways ) {

		if ( ! $this->gateway->is_configured() ) {
			return $payment_gateways;
		}

		$credentials = $this->gateway->get_credentials();

		$payment_gateways[ $this->gateway::get_id() ] = [
			'publishable_key' => $credentials['publishable_key'],
			'currency'        => strtolower( PaymentsHelpers::get_currency() ),
		];

		return $payment_gateways;
	}

	/**
	 * Get booking form service payment gateway data.
	 *
	 * @since 1.0.0
	 *
	 * @param array        $payment_gateways Payment gateways data.
	 * @param ServiceModel $service          Service model instance.
	 *
	 * @return array
	 */
	public function get_booking_form_service_gateway_data( $payment_gateways, $service ) {

		$override_enabled = Plugin::instance()->is_pro() && ( $service->override_payment_methods ?? false );

		// Check if gateway should be included based on override setting.
		if ( $override_enabled && ! in_array( $this->gateway::get_id(), $service->payment_gateways, true ) ) {
			// When override is ON, check service custom selection.
			return $payment_gateways;
		} elseif ( ! $override_enabled && ! isset( $payment_gateways[ $this->gateway::get_id() ] ) ) {
			// When override is OFF (using global defaults), check if gateway exists in passed array.
			return $payment_gateways;
		}

		// Bail if this gateway is not configured.
		if ( ! $this->gateway->is_configured() ) {
			return $payment_gateways;
		}

		$payment_gateways[ $this->gateway::get_id() ] = array_merge(
			$payment_gateways[ $this->gateway::get_id() ] ?? [],
			[
				'amount' => StripeHelpers::get_amount( $service->price ),
			]
		);

		return $payment_gateways;
	}

	/**
	 * Get booking form data.
	 *
	 * @since 1.0.0
	 *
	 * @param array $form_data Booking form data.
	 *
	 * @return array
	 */
	public function get_booking_form_data( $form_data ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh

		// Sanitize data.
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.NonceVerification.Recommended
		$input_data = wp_unslash( $_GET ?? [] );

		if ( ! PaymentsHelpers::is_redirect_url( $input_data, $this->gateway::get_id() ) ) {
			return $form_data;
		}

		$rules = [
			'payment_intent'               => 'required|string',
			'payment_intent_client_secret' => 'required|string',
			'redirect_status'              => 'required|string',
		];

		$sanitized_data = InputProcessor::process( $input_data, $rules );

		// Move form to confirmation step.
		$form_data['initialStepIndex'] = 5;

		if ( is_wp_error( $sanitized_data ) ) {
			$form_data['error'] = $sanitized_data->get_error_message();

			return $form_data;
		}

		// Bail if gateway is not configured.
		if ( ! $this->gateway->is_configured() ) {
			$form_data['error'] = __( 'Payment gateway not configured.', 'sugar-calendar-bookings-scheduling-appointments-lite' );

			return $form_data;
		}

		$authorize_data = [
			'id'            => $sanitized_data['payment_intent'],
			'client_secret' => $sanitized_data['payment_intent_client_secret'],
			'status'        => $sanitized_data['redirect_status'],
		];

		$payment = PaymentModel::query()
			->where( 'transaction_id', '=', $authorize_data['id'], '%s' )
			->where( 'status', '=', PaymentModel::STATUS_PENDING, '%s' )
			->first();

		if ( ! $payment ) {
			$form_data['error'] = __( 'Payment not found.', 'sugar-calendar-bookings-scheduling-appointments-lite' );

			return $form_data;
		}

		try {
			Plugin::get( StripePaymentGateway::class )
				->get_processor()
				->capture_payment( $payment, $authorize_data );
		} catch ( Exception $e ) {
			$form_data['error'] = $e->getMessage();
		}

		$appointment = $payment->appointments[0];

		$form_data = array_merge(
			$form_data,
			[
				// Empty customer override — see PaymentsController::capture
				// for the phone→email auto-merge oracle rationale.
				'appointment' => Plugin::get( BookingFormService::class )->get_appointment_form_data(
					$appointment,
					[
						'customer' => [
							'name'  => '',
							'email' => '',
							'phone' => '',
						],
					]
				),
				'payment'     => Plugin::get( PaymentService::class )->format_payment_data( $payment ),
			]
		);

		return $form_data;
	}

	/**
	 * Output footer scripts.
	 * Removes redirect-based payments query parameters.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function print_footer_scripts() {

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$input_data = wp_unslash( $_GET ?? [] );

		if ( ! PaymentsHelpers::is_redirect_url( $input_data, $this->gateway::get_id() ) ) {
			return;
		}

		$parameters_to_remove = [
			'payment_intent',
			'payment_intent_client_secret',
			'redirect_status',
			PaymentsHelpers::PAYMENT_CALLBACK_PARAMETER,
		];
		?>
		<script type="text/javascript">
			const url = new URL( window.location.href );

			<?php foreach ( $parameters_to_remove as $parameter ) : ?>
			url.searchParams.delete( "<?php echo esc_attr( $parameter ); ?>" );
			<?php endforeach; ?>

			history.replaceState( history.state, null, url.href );
		</script>
		<?php
	}
}
