<?php
/**
 * Shift4 Apple Pay gateway.
 *
 * @package flo-checkout
 *
 * @phpcs:disable Squiz.Commenting.FunctionComment.MissingParamTag
 */

namespace Flo_Checkout\Gateways;

use Exception;
use Flo_Checkout\Gateways\Apple_Pay\Merchant_Validator;
use Flo_Checkout\Gateways\Apple_Pay\Payment_Request_Factory;
use Flo_Checkout\Gateways\Apple_Pay\Requests\Apple_Pay_Refund_Request;
use Flo_Checkout\Gateways\Apple_Pay\Requests\Apple_Pay_Sale_Request;
use Flo_Checkout\Gateways\Apple_Pay\Responses\Apple_Pay_Refund_Response;
use Flo_Checkout\Gateways\Apple_Pay\Responses\Apple_Pay_Sale_Response;
use Flo_Checkout\Gateways\Shift4_APM\Abstract_APM_Gateway;
use Flo_Checkout\Gateways\Apple_Pay\Settings;
use Flo_Checkout\Gateways\Shift4_APM\Requests\Abstract_Request_Gateway_Payment;
use Flo_Checkout\Gateways\Shift4_APM\Responses\Response_Factory_Gateway;
use Flo_Checkout\Shared;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Data\Payment_Methods;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Data\Payment_Methods\Enums\Settings_Mode;
use WC_Order;

/**
 * Class Shift4_Apple_Pay
 */
class Shift4_Apple_Pay extends Abstract_APM_Gateway {

	private const AJAX_GET_PAYMENT_REQUEST = 'nm_checkout_apple_pay_payment_request';
	private const AJAX_VALIDATE_MERCHANT   = 'nm_checkout_apple_pay_validate_merchant';

	public const SHIFT4_APM_SALE_RESPONSE_TYPE   = 'apple_pay_sale';
	public const SHIFT4_APM_REFUND_RESPONSE_TYPE = 'apple_pay_refund';

	/**
	 * Store name.
	 *
	 * @var string
	 */
	public string $store_name;

	/**
	 * {@inheritDoc}
	 */
	public static function get_id(): string {
		return Payment_Methods::NMC_APPLE_PAY;
	}

	/**
	 * {@inheritDoc}
	 */
	public static function has_block_support(): bool {
		// TODO: To fix this we need to figure out how to update shipping and billing address in the checkout.
		// In /assets/src/Components/ApplePayContent.js we have an implementation for this, but it doesn't work.
		return false;
	}

	/**
	 * Set up the gateway.
	 */
	public function __construct() {
		$this->id = self::get_id();

		parent::__construct();

		$this->response_factory = new Response_Factory_Gateway( $this );

		$this->response_factory->add_class(
			self::SHIFT4_APM_SALE_RESPONSE_TYPE,
			Apple_Pay_Sale_Response::class
		);
		$this->response_factory->add_class(
			self::SHIFT4_APM_REFUND_RESPONSE_TYPE,
			Apple_Pay_Refund_Response::class
		);

		$this->store_name = $this->get_store_name();

		// Registers Apple Pay settings scripts.
		add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) );

		if ( 'yes' === $this->enabled ) {
			add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );

			$this->shared->ajax->add_action(
				self::AJAX_VALIDATE_MERCHANT,
				array( new Merchant_Validator( $this ), 'ajax_validate_merchant' ),
				true
			);

			$this->shared->ajax->add_action(
				self::AJAX_GET_PAYMENT_REQUEST,
				array( new Payment_Request_Factory( $this ), 'ajax_get_request' ),
				true
			);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public function get_apm_payment_method(): string {
		return 'applepay';
	}

	/**
	 * Get the store name for Apple Pay.
	 *
	 * @return string
	 */
	private function get_store_name(): string {
		$store_name = $this->get_option( 'store_name' );
		return ! empty( $store_name ) ? $store_name : get_bloginfo( 'name' );
	}

	/**
	 * Register admin scripts.
	 *
	 * @return void
	 */
	public function admin_scripts(): void {
		wp_enqueue_script(
			'flo-checkout-apple-pay-admin',
			Shared::instance()->assets->get_package_assets_url() . 'js/admin/flo_apple_pay_settings.js',
			array( 'jquery' ),
			filemtime( Shared::instance()->assets->get_package_assets_path() . 'js/admin/flo_apple_pay_settings.js' ),
			true
		);

		wp_localize_script(
			'flo-checkout-apple-pay-admin',
			'nm_apple_pay_settings',
			array(
				'payment_method_id' => $this->id,
				'modes'             => array(
					'prod' => Settings_Mode::PRODUCTION->value,
					'int'  => Settings_Mode::INTEGRATION->value,
				),
			)
		);
	}

	/**
	 * Enqueue scripts.
	 */
	public function enqueue_scripts(): void {
		if ( is_checkout() ) {
			wp_enqueue_script(
				'apple-pay-sdk',
				'https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js',
				array(),
				'1.0.0',
				true
			);

			wp_enqueue_script(
				'flo-apple-pay',
				$this->shared->package_info->paths->get_url() . 'assets/js/flo_apple_pay.js',
				array( 'jquery', 'apple-pay-sdk', 'ajax-script-shared' ),
				filemtime( $this->shared->package_info->paths->get_path() . 'assets/js/flo_apple_pay.js' ),
				true
			);

			wp_localize_script(
				'flo-apple-pay',
				'floApplePay',
				array(
					'payment_method_id'        => $this->id,
					'payment_data_name'        => $this->get_payment_data_form_field_name(),
					'merchant_validation_ajax' => $this->shared->ajax->get_action( self::AJAX_VALIDATE_MERCHANT )?->get_data_for_js(),
					'payment_request_ajax'     => $this->shared->ajax->get_action( self::AJAX_GET_PAYMENT_REQUEST )?->get_data_for_js(),
					'i18n'                     => array(
						'apple_pay_not_supported'   => __( 'Apple Pay is not supported on this device.', 'flo-checkout-plugin' ),
						'merchant_validation_error' => __( 'An error occurred while validating the merchant. Please contact us if this problem persists.', 'flo-checkout-plugin' ),
						'billing_validation'        => array(
							'givenName'    => __( 'First name is required.', 'flo-checkout-plugin' ),
							'familyName'   => __( 'Last name is required.', 'flo-checkout-plugin' ),
							'emailAddress' => __( 'Email is not valid.', 'flo-checkout-plugin' ),
							'phoneNumber'  => __( 'Phone number is not valid', 'flo-checkout-plugin' ),
							'addressLines' => __( 'At least one address line is required.', 'flo-checkout-plugin' ),
							'locality'     => __( 'City is required.', 'flo-checkout-plugin' ),
							'postalCode'   => __( 'Postal code is required.', 'flo-checkout-plugin' ),
							'countryCode'  => __( 'Only Swedish billing addresses are supported.', 'flo-checkout-plugin' ),
						),
					),
				)
			);
		}
	}

	/**
	 * Initialise Gateway Settings Form Fields
	 */
	public function init_form_fields(): void {
		$this->form_fields = Settings::get_settings_fields();
	}

	/**
	 * {@inheritDoc}
	 *
	 * @throws Exception If the payment data is missing.
	 */
	protected function process_payment_data( mixed $payment_data ): mixed {
		if ( empty( $payment_data ) ) {
			throw new Exception(
				esc_html__( 'Apple Pay token is missing.', 'flo-checkout-plugin' )
			);
		}

		if ( is_array( $payment_data ) ) {
			$payment_data = wp_json_encode( $payment_data );
		}

		return $payment_data;
	}

	/**
	 * {@inheritDoc}
	 */
	protected function get_payment_request_handler( Abstract_APM_Gateway $gateway, ?WC_Order $order = null ): Abstract_Request_Gateway_Payment {
		return new Apple_Pay_Sale_Request( $gateway, $order );
	}

	/**
	 * {@inheritDoc}
	 *
	 * @throws Exception If the refund link is not found.
	 */
	protected function get_refund_request_handler( Abstract_APM_Gateway $gateway, ?WC_Order $order = null, ?float $amount = null ): Abstract_Request_Gateway_Payment {
		return new Apple_Pay_Refund_Request(
			$this,
			$order,
			$amount
		);
	}
}
