<?php
/**
 * Handles Swish connection tests.
 *
 * @package flo-checkout
 */

namespace Flo_Checkout\Gateways\Swish;

use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Modules\Loggers\Log_Level_Enum;

defined( 'ABSPATH' ) || exit;

/**
 * Swish connection test class.
 */
class Swish_Connection_Test {

	/**
	 * Set up Swish payment configuration.
	 *
	 * This method sets up the necessary actions for Swish payment integration.
	 *
	 * @return void
	 */
	public static function setup(): void {
		add_action(
			'wp_ajax_swish_pay_test_connection',
			array( self::class, 'connection_test' )
		);

		add_action(
			'woocommerce_api_swish_pay_gateway_connection_test',
			array(
				self::class,
				'swish_callback_connection_test',
			),
			10,
			0
		);
		add_action(
			'wp_ajax_swish_pay_abort_test_payment',
			array( self::class, 'abort_connection_test_request' )
		);
	}

	/**
	 * Function called by AJAX to abort Swish payment request.
	 *
	 * @return void
	 */
	public static function abort_connection_test_request(): void {
		if ( ! wp_verify_nonce( $_POST['nonce'], 'flo_swish_settings_abort_request' ) ) {
			wp_send_json_error( 'Invalid nonce' );
		}

		$request_id = sanitize_text_field( stripslashes( $_POST['payment_id'] ?? '' ) );
		$response   = self::abort_request( $request_id );

		if ( $response && $response['status'] ) {
			wp_send_json_success( __( 'Request canceled', 'flo-checkout-plugin' ) );
		} else {
			wp_send_json_error( __( 'Could not cancel request', 'flo-checkout-plugin' ) );
		}
	}

	/**
	 * Abort Swish payment request.
	 *
	 * @param string $request_id Swish payment request ID.
	 *
	 * @return array|bool Response from Swish API. Or false if called incorrectly.
	 */
	public static function abort_request( string $request_id ): bool|array {
		if ( 'mss' === Swish_Settings::get( 'swish_environment' ) ) { // MSS requests cannot be aborted.
			return false;
		}

		if ( empty( $request_id ) ) {
			return false;
		}

		return Swish_API::api_request(
			array(
				array(
					'op'    => 'replace',
					'path'  => '/status',
					'value' => 'cancelled',
				),
			),
			"paymentrequests/$request_id",
			'PATCH'
		);
	}

	/**
	 * Test Swish connection. Response is sent as JSON, then WP dies.
	 *
	 * @return void
	 */
	public static function connection_test(): void {
		if ( ! wp_verify_nonce( $_POST['nonce'], 'flo_swish_settings' ) ) {
			wp_send_json_error( 'Invalid nonce' );
		}

		if ( ! Swish_Settings::is_setting_enabled( 'swish_connection_test_enabled' ) ) {
			wp_send_json_success( '' );
		}

		$payee_number = Swish_Settings::get_swish_setting( 'payee_number' );

		$swish_connection_test_payer = Swish_Settings::get( 'test_payer_number' );

		$error_message = false;

		if ( empty( $payee_number ) ) {
			$error_message = __( 'Please enter Merchant Swish number', 'flo-checkout-plugin' );
		}

		if ( empty( Swish_Settings::get_swish_setting( 'api_end_url' ) ) ) {
			$error_message = __( 'Please enter API URL', 'flo-checkout-plugin' );
		}

		if ( empty( Swish_Settings::get_swish_setting( 'public_certificate' ) ) ) {
			$error_message = __( 'Please enter Swish certificate', 'flo-checkout-plugin' );
		}

		if ( empty( Swish_Settings::get_swish_setting( 'root_certificate' ) ) ) {
			$error_message = __( 'Swish Root certificate missing', 'flo-checkout-plugin' );
		}

		if ( 'prod' === Swish_Settings::get( 'swish_environment' ) && empty( $swish_connection_test_payer ) ) {
			$error_message = __( 'When testing the production environment you have to enter a real payer number.', 'flo-checkout-plugin' );
		}

		if ( ! $error_message ) {
			$test_payer = '46701740635';

			if ( ! empty( $swish_connection_test_payer ) ) {
				$test_payer = $swish_connection_test_payer;
				if ( '0' === $test_payer[0] ) {
					$test_payer = '46' . substr( $test_payer, 1 );
				}
			}

			$callback_url = Swish_Client::get_callback_url(
				'test_connection',
				'payment',
				'swish_pay_gateway_connection_test'
			);

			$request_id          = Swish_Request_IDs::generate();
			$callback_identifier = Swish_Request_IDs::generate();

			set_transient(
				'swish_test_connection_callback_id',
				$callback_identifier,
				MINUTE_IN_SECONDS * 5
			);

			$response = Swish_API::api_request(
				array(
					'payeePaymentReference' => '0123456789',
					'callbackUrl'           => $callback_url,
					'payerAlias'            => $test_payer,
					'payeeAlias'            => $payee_number,
					'amount'                => '1',
					'currency'              => 'SEK',
					'message'               => 'Northmill Test Product',
					'callbackIdentifier'    => $callback_identifier,
				),
				"paymentrequests/$request_id",
				'PUT',
				'v2'
			);

			if ( $response['status'] ) {
				wp_send_json_success(
					array(
						'message'    => '<strong style="color: green;">' . __( 'Connection test successful', 'flo-checkout-plugin' ) . '</strong>',
						'payment_id' => $request_id,
					)
				);
			} else {
				$error_message = $response['response_technical'] ?? '';
			}
		} else {
			$error_message = __( 'Invalid connection settings', 'flo-checkout-plugin' ) . ': ' . $error_message;
		}

		wp_send_json_error( '<strong style="color: red;">' . $error_message . '</strong>' );
	}

	/**
	 * Handle Swish connection test callback.
	 *
	 * @return void
	 *
	 * @phpcs:disable WordPress.Security.NonceVerification.Recommended
	 */
	public static function swish_callback_connection_test(): void {
		Swish_Settings::log(
			'swish_callback_response_CONNECTION_TEST',
			array(
				'request' => $_REQUEST,
			)
		);

		if ( $_REQUEST['event'] ) {
			$event_type = $_REQUEST['event'];

			if ( 'payment' === $event_type || 'refund' === $event_type ) {
				$order_id = $_REQUEST['order_id'];

				$callback_identifier = get_transient( 'swish_test_connection_callback_id' );

				$swish_client      = new Swish_Client();
				$is_valid_callback = $swish_client->is_callback_valid(
					$order_id,
					$callback_identifier
				);

				if ( $is_valid_callback ) {
					$request_body = file_get_contents( 'php://input' );
					$json         = json_decode( $request_body );

					if ( empty( $request_body ) ) {
						Swish_Settings::log(
							'Request body missing for Swish test connection',
							array(
								'order_id' => $order_id,
							),
							Log_Level_Enum::ERROR
						);
						wp_die();
					}

					Swish_Settings::log(
						'Swish test request body details',
						array(
							'order_id' => $order_id,
							'body'     => $request_body,
						)
					);

					switch ( $json->status ) {
						case 'DECLINED':
							Swish_Settings::log( 'Test payment declined by user' );
							break;
						case 'ERROR':
							$error_details = Swish_Errors::get_message_by_code( $json->errorCode );

							Swish_Settings::log(
								'Test payment error',
								array(
									'order_id' => $order_id,
									'error'    => $error_details,
								)
							);
							break;
						case 'DEBITED':
							Swish_Settings::log( 'TEST Got DEBITED from Swish' );
							break;
						case 'PAID':
							if ( 'refund' !== $event_type ) {
								Swish_Settings::log( 'TEST Got PAID from Swish' );
							}
							if ( 'refund' === $event_type ) {
								Swish_Settings::log( 'TEST Successfully credited to customer account' );
							}
							break;
					}

					$return_result['success']     = true;
					$return_result['successCode'] = '200';

					// Send received notification to server.
					wp_send_json( $return_result, $return_result['successCode'] );

				} else {
					Swish_Settings::log(
						'Invalid Swish customer',
						array(
							'order_id'            => $order_id,
							'callback_identifier' => $callback_identifier,
						),
						Log_Level_Enum::ERROR
					);
				}

				Swish_Settings::log( 'swish_callback_response CONNECTION_TEST End' );
			}
		}
	}
	// @phpcs:enable
}
