<?php

// Exit if the file is accessed directly
if ( ! defined( 'ABSPATH' ) ) exit;

// Include plugin library
require_once ( plugin_dir_path( __FILE__ ) . 'lib/paypal-purchase/paypal.class.php' );

if ( ! class_exists( 'WPJobster_PayPal_Loader' ) ) {

	class WPJobster_PayPal_Loader extends \stdClass {

		public function __construct( $gateway = 'paypal' ) {
			// Define gateway slug
			$this->unique_id = 'paypal';

			// Add gateway to payment methods list
			add_filter( 'wpj_payment_gateways_filter', function( $payment_gateways_list ) {
				$payment_gateways_list[$this->unique_id] = __( 'PayPal', 'wpjobster' );
				return $payment_gateways_list;
			}, 10, 1 );

			// Add gateway option to admin
			add_filter( 'wpj_admin_settings_items_filter', function( $menu ) {
				$menu['payment-gateways']['childs'][$this->unique_id] = array( 'order' => '02a', 'path' => get_template_directory() . '/lib/plugins/wpjobster-paypal/admin-fields.php' );
				return $menu;
			}, 10, 1 );

			// Add gateway to payment process flow
			add_action( 'wpjobster_taketo_' . $this->unique_id . '_gateway', array( $this, 'initializePayment' ), 10, 2 );
			add_action( 'wpjobster_processafter_' . $this->unique_id . '_gateway', array( $this, 'processPayment' ), 10, 2 );

			// Set gateway currencies
			add_filter( 'wpjobster_take_allowed_currency_' . $this->unique_id, array( $this, 'setGatewayCurrencies' ) );

			// Delete the subscription from gateway when it's cancelled on the theme
			add_action( 'wpj_before_subscription_removal', array( $this, 'deleteLiveSubscription' ), 10, 1 );

			// Init payment library class
			$this->p = new paypal_class;
		}

		public static function init() { $class = __CLASS__; new $class; }

		public function initializePayment( $payment_type, $order_details ) { // params from gateways/init.php
			// Payment ROW
			$payment_row = wpj_get_payment( array( 'payment_type_id' => $order_details['id'], 'payment_type' => $payment_type ) );

			// Callback URL
			$callback_url = get_bloginfo( 'url' ) . '/?payment_response=' . $this->unique_id . '&payment_id=' . $payment_row->id;

			// Send data to PayPal
			$this->p->add_field( 'business'     , wpj_get_option( 'wpjobster_paypal_email' ) );
			$this->p->add_field( 'currency_code', $payment_row->final_amount_currency );
			$this->p->add_field( 'return'       , $callback_url . '&action=paid' );
			$this->p->add_field( 'cancel_return', $callback_url . '&action=cancelled' );
			$this->p->add_field( 'notify_url'   , $callback_url . '&action=ipn' );
			$this->p->add_field( 'item_name'    , apply_filters( 'wpj_gateway_order_title_filter', wpj_get_title_by_payment_type( $payment_type, $order_details ), $order_details, $payment_type ) );
			$this->p->add_field( 'item_number'  , $order_details['id'] );
			$this->p->add_field( 'charset'      , get_bloginfo( 'charset' ) );
			$this->p->add_field( 'amount'       , $payment_row->final_amount_exchanged );
			$this->p->add_field( 'custom'       , $payment_row->id );
			$this->p->add_field( 'key'          , md5( date( "Y-m-d:" ) . rand() ) );

			// Send subscription data to PayPal
			if ( $payment_type == 'subscription' && $order_details['plan'] != 'lifetime' ) {
				$this->p->add_field( 'cmd'    , '_xclick-subscriptions' );
				$this->p->add_field( 'no_note', 1 );
				$this->p->add_field( 'src'    , 1 );
				$this->p->add_field( 'a3'     , $payment_row->final_amount_exchanged );
				$this->p->add_field( 'p3'     , wpj_get_subscription_cycle_and_period( $order_details['plan'], 'period' ) );
				$this->p->add_field( 't3'     , wpj_get_subscription_cycle_and_period( $order_details['plan'], 'cycle' ) );
				$this->p->add_field( 'bn'     , 'PP-SubscriptionsBF:btn_subscribeCC_LG.gif:NonHostedGuest' );
			}

			// Submit form to PayPal
			$this->p->submit_paypal_post();
		}

		public function processPayment( $payment_type, $payment_type_class ) { // params from gateways/init.php
			if ( isset( $_REQUEST['payment_id'] ) || isset( $_REQUEST['custom'] ) ) {
				$payment_id       = isset( $_REQUEST['payment_id'] ) ? $_REQUEST['payment_id'] : $_REQUEST['custom'];
				$payment_row      = wpj_get_payment( array( 'id' => $payment_id ) );

				$order_id         = $payment_row->payment_type_id;
				$payment_type     = $payment_row->payment_type;

				$order            = wpj_get_order_by_payment_type( $payment_type, $order_id );

				$payment_response = json_encode( $_REQUEST );
				$response_decoded = wpj_json_decode( $payment_response );
				$payment_status   = isset( $response_decoded->payment_status ) ? strtolower( $response_decoded->payment_status ) : '';
				$payment_details  = $payment_type == 'subscription' && isset( $_POST['subscr_id'] ) ? WPJ_Form::post( 'subscr_id' ) : WPJ_Form::post( 'txn_id' );

				// Save response
				if ( isset( $response_decoded->verify_sign ) ) {
					$webhook = wpj_save_webhook( array(
						'webhook_id'       => $response_decoded->verify_sign,
						'payment_id'       => $response_decoded->custom,
						'status'           => $payment_status,
						'type'             => WPJ_Form::get( 'action' ) . ' ' . WPJ_Form::post( 'txn_type' ),
						'description'      => $response_decoded->item_name,
						'amount'           => isset( $response_decoded->mc_gross ) ? $response_decoded->mc_gross : WPJ_Form::post( 'mc_amount3' ),
						'amount_currency'  => $response_decoded->mc_currency,
						'fees'             => isset( $response_decoded->mc_fee ) ? $response_decoded->mc_fee : 0,
						'fees_currency'    => $response_decoded->mc_currency,
						'create_time'      => isset( $response_decoded->payment_date ) ? strtotime( $response_decoded->payment_date ) : current_time( 'timestamp', 1 ),
						'payment_response' => $payment_response,
						'payment_type'     => $payment_type,
						'order_id'         => $order_id
					) );
				}

				// Apply response to order
				if ( isset( $_SERVER['HTTP_REFERER'] ) && ( $_SERVER['HTTP_REFERER'] == 'https://www.sandbox.paypal.com/' || $_SERVER['HTTP_REFERER'] == 'https://www.paypal.com/' ) ) {
					if ( WPJ_Form::get( 'action' ) == 'cancelled' && $order->payment_status != 'cancelled' ) { // mark order as cancelled
						do_action( "wpjobster_" . $payment_type . "_payment_failed", $order_id, $this->unique_id, 'Buyer clicked cancel', $payment_response );

					} elseif ( WPJ_Form::get( 'action' ) == 'paid' && $order->payment_status != 'completed' ) { // mark order as paid
						do_action( "wpjobster_" . $payment_type . "_payment_success", $order_id, $this->unique_id, $payment_details, $payment_response );

					}

				} else { // ipn
					if ( WPJ_Form::get( 'action' ) == 'ipn' ) {
						if ( $this->p->validate_ipn() ) { // validate IPN
							if ( $this->validateTransaction( $payment_row ) ) { // validate transaction
								if ( WPJ_Form::post( 'txn_type' ) == 'subscr_signup' ) return false;

								if ( $payment_status == 'completed' || $payment_status == 'processed' ) { // mark order as completed
									do_action( "wpjobster_" . $payment_type . "_payment_success", $order_id, $this->unique_id, $payment_details, $payment_response );

									// update profile ID to cancel subscription on merchant site
									if ( $payment_type == 'subscription' ) {
										wpj_update_subscription_order(
											['profile_id' => WPJ_Form::post( 'subscr_id' ), 'payment_gateway_transaction_id' => WPJ_Form::post( 'subscr_id' )],
											['id' => $order_id]
										);
									}

								} elseif ( $payment_status == 'denied' || $payment_status == 'expired' || $payment_status == 'failed' || WPJ_Form::post( 'txn_type' ) == 'subscr_cancel' ) { // mark order as failed
									do_action( "wpjobster_" . $payment_type . "_payment_failed", $order_id, $this->unique_id, 'Failed', $payment_response );

								} else { // mark order as pending
									do_action( "wpjobster_" . $payment_type . "_payment_other", $order_id, $this->unique_id, WPJ_Form::post( 'txn_type' ), $payment_response, $payment_status );

								}
							}
						}
					}
				}
			}
		}

		public function setGatewayCurrencies( $currency ) {
			// if the gateway requires a specific currency you can declare it there
			// currency conversions are done automatically
			global $wpjobster_currencies_array;

			$currency = wpj_get_site_currency();

			$accepted_paypal_currencies = array( 'AUD', 'BRL', 'CAD', 'CZK', 'DKK', 'EUR', 'HKD', 'HUF', 'INR', 'ILS', 'JPY', 'MYR', 'MXN', 'TWD', 'NZD', 'NOK', 'PHP', 'PLN', 'GBP', 'RUB', 'SGD', 'SEK', 'CHF', 'THB', 'USD' );

			// if currency not supported
			if ( ! in_array( $currency, $accepted_paypal_currencies ) ) {

				// fallback
				$currency = 'USD';

				// try other site currencies
				foreach ( $wpjobster_currencies_array as $wpjobster_currency ) {
					if ( in_array( $wpjobster_currency, $accepted_paypal_currencies ) ) {
						$currency = $wpjobster_currency; break;
					}
				}
			}

			return $currency;
		}

		public function validateTransaction( $payment ) {
			$final_amount = WPJ_Form::post( 'mc_gross' );
			if ( ! $final_amount ) $final_amount = WPJ_Form::post( 'mc_amount3' );

			$business_email = isset( $_POST['business'] ) && is_email( $_POST['business'] ) ? trim( $_POST['business'] ) : '';
			if ( empty( $business_email ) )
				$business_email = isset( $_POST['receiver_email'] ) && is_email( $_POST['receiver_email'] ) ? trim( $_POST['receiver_email'] ) : '';

			// verify payment recipient
			if ( strcasecmp( $business_email, trim( wpj_get_option( 'wpjobster_paypal_email' ) ) ) != 0 ) return false;

			// verify payment currency
			if ( strtoupper( WPJ_Form::post( 'mc_currency' ) ) != strtoupper( $payment->final_amount_currency ) ) return false;

			// verify payment amount
			if ( number_format( ( float ) $final_amount, 2 ) < number_format( ( float ) $payment->final_amount_exchanged, 2 ) ) return false;

			return true;
		}

		public function deleteLiveSubscription( $order_id ) {
			$subscription_order = wpj_get_subscription_order( 'payment_gateway_name, payment_gateway_transaction_id, profile_id', ['id' => $order_id], 'row' );

			if ( isset( $subscription_order->payment_gateway_name ) && $subscription_order->payment_gateway_name == 'paypal' ) {

				if ( wpj_get_option( 'wpjobster_paypal_enable_sandbox' ) == "yes" ) $paypal_url = 'https://api-3t.sandbox.paypal.com/nvp';
				else $paypal_url = 'https://api-3t.paypal.com/nvp';

				$profile_id = $subscription_order->payment_gateway_transaction_id;

				if ( $profile_id == get_current_user_id() ) $profile_id = $subscription_order->profile_id;

				if ( $profile_id != get_current_user_id() ) {
					$api_request = 'USER=' . urlencode( wpj_get_option( 'wpjobster_theme_apiusername' ) )
								.  '&PWD=' . urlencode( wpj_get_option( 'wpjobster_theme_apipassword' ) )
								.  '&SIGNATURE=' . urlencode( wpj_get_option( 'wpjobster_theme_apisignature' ) )
								.  '&VERSION=76.0'
								.  '&METHOD=ManageRecurringPaymentsProfileStatus'
								.  '&PROFILEID=' . urlencode( $profile_id )
								.  '&ACTION=' . urlencode( 'Cancel' )
								.  '&NOTE=' . urlencode( 'Profile cancelled at store' );

					$ch = curl_init();
					curl_setopt( $ch, CURLOPT_URL, $paypal_url );
					curl_setopt( $ch, CURLOPT_VERBOSE, 1 );

					curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
					curl_setopt( $ch, CURLOPT_POST, 1 );

					// Set the API parameters for this transaction
					curl_setopt( $ch, CURLOPT_POSTFIELDS, $api_request );

					// Request response from PayPal
					$response = curl_exec( $ch );

					// If no response was received from PayPal there is no point parsing the response
					if ( ! $response )
						die( 'Calling PayPal to change_subscription_status failed: ' . curl_error( $ch ) . '(' . curl_errno( $ch ) . ')' );

					curl_close( $ch );

					parse_str( $response, $parsed_response );

					return $parsed_response;
				}

			}
		}

	} // END CLASS

} // END IF CLASS EXIST

add_action( 'after_setup_theme', array( 'WPJobster_PayPal_Loader', 'init' ) );