<?php
namespace SabaiApps\Directories\Component\PaymentGateway\Gateway;

use SabaiApps\Directories\Component\Payment\IOrder;
use SabaiApps\Directories\Component\Payment\IPlan;
use SabaiApps\Directories\Component\Entity\Type\IEntity;
use SabaiApps\Directories\Context;
use SabaiApps\Directories\Request;
use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\SandboxEnvironment;
use PayPalCheckoutSdk\Core\ProductionEnvironment;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
use PayPalCheckoutSdk\Orders\OrdersGetRequest;

class PaypalGateway extends AbstractGateway {

	protected function _paymentGatewayInfo() {
		return array(
			'label'            => 'PayPal',
			'default_settings' => array(
				'client_id'    => null,
				'secret'       => null,
				'sb_enable'    => false,
				'sb_client_id' => null,
				'sb_secret'    => null,
			),
			'plan_types'       => array( 'base', 'addon' ),
		);
	}

	public function paymentGatewaySettingsForm( array $settings, array $parents ) {
		return array(
			'client_id'    => array(
				'#title'            => __( 'PayPal client ID', 'directories-pro' ),
				'#type'             => 'textfield',
				'#default_value'    => $settings['client_id'],
				'#required'         => function ( $form ) use ( $parents ) {
					return $form->getValue( array_merge( $parents, array( 'sb_enable' ) ) ) ? false : true; },
				'#display_required' => false,
			),
			'secret'       => array(
				'#title'            => __( 'PayPal secret', 'directories-pro' ),
				'#type'             => 'textfield',
				'#default_value'    => $settings['secret'],
				'#required'         => function ( $form ) use ( $parents ) {
					return $form->getValue( array_merge( $parents, array( 'sb_enable' ) ) ) ? false : true; },
				'#display_required' => false,
			),
			'sb_enable'    => array(
				'#title'         => __( 'Enable sandbox mode', 'directories-pro' ),
				'#type'          => 'checkbox',
				'#default_value' => ! empty( $settings['sb_enable'] ),
				'#required'      => function ( $form ) use ( $parents ) {
					return (bool) $form->getValue( array_merge( $parents, array( 'sb_enable' ) ) ); },
			),
			'sb_client_id' => array(
				'#title'         => __( 'PayPal sandbox client ID', 'directories-pro' ),
				'#type'          => 'textfield',
				'#default_value' => $settings['sb_client_id'],
				'#required'      => function ( $form ) use ( $parents ) {
					return (bool) $form->getValue( array_merge( $parents, array( 'sb_enable' ) ) ); },
				'#states'        => array(
					'visible' => array(
						sprintf( '[name="%s"]', $this->_application->Form_Form_fieldName( array_merge( $parents, array( 'sb_enable' ) ) ) ) => array(
							'type'  => 'checked',
							'value' => true,
						),
					),
				),
			),
			'sb_secret'    => array(
				'#title'         => __( 'PayPal sandbox secret', 'directories-pro' ),
				'#type'          => 'textfield',
				'#default_value' => $settings['sb_secret'],
				'#required'      => true,
				'#states'        => array(
					'visible' => array(
						sprintf( '[name="%s"]', $this->_application->Form_Form_fieldName( array_merge( $parents, array( 'sb_enable' ) ) ) ) => array(
							'type'  => 'checked',
							'value' => true,
						),
					),
				),
			),
		);
	}

	public function paymentGatewayCheckoutForm( Context $context, $planOrOrder, ?IEntity $entity = null, $action = null, array $parents = array(), $discountCodesFormFieldName = null ) {
		$button_id = 'drts-payment-checkout-paypal-button';
		$order_url = (string) $this->_getCheckoutActionUrl( 'order', $context, 'json' );
		$js        = '
paypal.Buttons({
    style: {
        //color: "gold", // blue, silver, white, black
        //layout: "horizontal",
        //shape: "pill" // rect
    },
    createOrder: function() {
        var button = document.getElementById("' . $button_id . '");
        var form = button.closest("form");
        var inputs = form.querySelectorAll("input[name=\"' . $discountCodesFormFieldName . '[]\"]");
        var codes = Array.from(inputs).map(input => input.value);
        var formData = new FormData();
        codes.forEach(code => {
            formData.append("' . $discountCodesFormFieldName . '[]", code);
        });
        return fetch("' . $order_url . '", {
            method: "POST",
            body: formData,
        }).then(function(res) {
            if (res.ok) {
                return res.json();
            } else {
                throw Error();
            }
        }).then(function(result) {
            return result.id;
        }).catch(function(err){
            console.log(err);
        });
    },
    onApprove: function(data, actions) {
        document.getElementById("' . $button_id . '").style.display = "none";
        DRTS.ajaxLoader(null, false, "body");
        return actions.order.capture().then(function(details) {
            var url;
            if (details.status === "COMPLETED") {
                url = "' . (string) $this->_getCheckoutActionUrl( 'success', $context ) . '&paypal_order_id=" + data.orderID;
            } else {
                url = "' . (string) $this->_getCheckoutActionUrl( 'cancel', $context ) . '&capture_failed=1&paypal_order_id=" + data.orderID;
            }
            window.location.href = url;
        });
    },
    onCancel: function(data, actions) {
        document.getElementById("' . $button_id . '").style.display = "none";
        DRTS.ajaxLoader(null, false, "body");
        window.location.href = "' . (string) $this->_getCheckoutActionUrl( 'cancel', $context ) . '&paypal_order_id=" + data.orderID;
    }
}).render("#' . $button_id . '");';
		$this->_loadPayPalJsFile();
		return array(
			'#type'     => 'item',
			'#markup'   => '<div id="' . $button_id . '"></div>',
			'#js_ready' => $js,
		);
	}

	protected function _loadPayPalJsFile() {
		$settings   = $this->_getSettings();
		$paypal_url = sprintf(
			'https://www.paypal.com/sdk/js?client-id=%s&currency=%s&disable-funding=credit,card',
			empty( $settings['sb_enable'] ) ? $settings['client_id'] : $settings['sb_client_id'],
			$this->_application->Payment_Components_impl( 'default' )->paymentGetCurrency()
		);
		$this->_application->getPlatform()->addJsFile( $paypal_url, 'paypal', array(), false, false, false, '' );
	}

	public function paymentGatewayOnLoadAssets() {
		$this->_loadPayPalJsFile();
	}

	public function paymentGatewayOnCheckoutAction( Context $context, $checkoutAction, $planOrOrder = null, ?IEntity $entity = null, $action = null, array $discountCodes = array() ) {
		switch ( $checkoutAction ) {
			case 'order':
				if ( ! Request::isPostMethod() ) {
					return false;
				}

				if ( $planOrOrder instanceof IOrder ) {
					$order = $planOrOrder->getOrder();
				} elseif ( $planOrOrder instanceof IPlan ) {
					if ( ! $order = $this->_createOrder( $planOrOrder, $entity, $action, $discountCodes ) ) {
						return false;
					}
				} else {
					return false;
				}

				$paypal_order = $this->_createPayPalOrder( $order );
				if ( $paypal_order->status !== 'CREATED' ) {
					$this->_deleteOrder( $order );
					return false;
				}

				$context->addTemplate( 'system_list' )->setAttributes( array( 'list' => $paypal_order ) );
				return true;

			case 'success':
				if ( ( ! $paypal_order_id = $context->getRequest()->asStr( 'paypal_order_id' ) )
					|| ( ! $order = $this->_getOrderByPayPalOrderId( $paypal_order_id ) )
					|| ! $this->_completeOrder( $order, $paypal_order_id )
				) {
					return false;
				}

				$context->paymentgateway_checkout_order_id = $order->getId();
				return true;

			case 'cancel':
				if ( ( ! $paypal_order_id = $context->getRequest()->asStr( 'paypal_order_id' ) )
					|| ( ! $order = $this->_getOrderByPayPalOrderId( $paypal_order_id ) )
					|| ! $this->_cancelOrder( $order, array( 'note' => __( 'Checkout process was cancelled.', 'directories-pro' ) ) )
				) {
					return false;
				}

				if ( $context->getRequest()->asBool( 'capture_failed' ) ) {
					$context->addFlash( __( 'PayPal could not capture your payment.', 'directories-pro' ), 'danger' );
				}
				$context->paymentgateway_checkout_order_id = 0;
				return true;
		}
	}

	protected function _getOrderByPayPalOrderId( $orderId ) {
		if ( ( ! $paypal_order = $this->_getPayPalOrder( $orderId ) )
			|| empty( $paypal_order->purchase_units[0]->custom_id )
			|| ( ! $order = $this->_application->Entity_Entity( 'post', $paypal_order->purchase_units[0]->custom_id ) )
		) {
			return false;
		}

		return $order;
	}

	protected function _createPayPalOrder( IEntity $order ) {
		$request = new OrdersCreateRequest();
		$request->prefer( 'return=representation' );
		$request->body = array(
			'intent'         => 'CAPTURE',
			'purchase_units' => array(
				0 => array(
					'amount'    => array(
						'currency_code' => $order->getSingleFieldValue( 'paymentgateway_order', 'data' )['currency'],
						'value'         => $this->_application->PaymentGateway_Order_totalAmount( $order ),
					),
					'custom_id' => $order->getId(),
				),
			),
		);
		$response      = $this->_getClient()->execute( $request );
		return $response->result;
	}

	protected function _getPayPalOrder( $orderId ) {
		$response = $this->_getClient()->execute( new OrdersGetRequest( $orderId ) );
		return $response->result;
	}

	protected function _getClient() {
		$settings = $this->_getSettings();
		$env      = empty( $settings['sb_enable'] ) ?
			new ProductionEnvironment( $settings['client_id'], $settings['secret'] ) :
			new SandboxEnvironment( $settings['sb_client_id'], $settings['sb_secret'] );
		return new PayPalHttpClient( $env );
	}
}
