<?php
/**
 * @version		$Id$
 * @package		mymuse
 * @copyright	Copyright © 2025 - Arboreta Internet Services - All rights reserved.
 * @license		GNU/GPL
 * @author		Gordon Fisch
 * @author mail	info@joomlamymuse.com
 * @website		http://www.joomlamymuse.com
 */


// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

use Joomla\CMS\Language\Language;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Router\Route;
use Joomla\Database\DatabaseDriver;
use Joomla\Database\ParameterType;
use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\HTML\HTMLHelper;

use Joomla\CMS\Categories\Categories;
use Joomla\CMS\Categories\CategoryNode;
use Joomla\Component\Mymuse\Administrator\Table\OrderTable;
use Joomla\CMS\User\UserHelper;
use Joomla\CMS\Http\Response;


require __DIR__ . "/vendor/autoload.php";

use PaypalServerSdkLib\PaypalServerSdkClientBuilder;
use PaypalServerSdkLib\Authentication\ClientCredentialsAuthCredentialsBuilder;
use PaypalServerSdkLib\Logging\LoggingConfigurationBuilder;
use PaypalServerSdkLib\Logging\RequestLoggingConfigurationBuilder;
use PaypalServerSdkLib\Logging\ResponseLoggingConfigurationBuilder;
use Psr\Log\LogLevel;
use PaypalServerSdkLib\Models\Builders\OrderRequestBuilder;
use PaypalServerSdkLib\Models\CheckoutPaymentIntent;
use PaypalServerSdkLib\Models\Builders\PurchaseUnitRequestBuilder;
use PaypalServerSdkLib\Models\Builders\AmountWithBreakdownBuilder;
use PaypalServerSdkLib\Models\Builders\AmountBreakdownBuilder;
use PaypalServerSdkLib\Models\Builders\MoneyBuilder;
use PaypalServerSdkLib\Models\Builders\ItemBuilder;
use PaypalServerSdkLib\Models\ItemCategory;
use PaypalServerSdkLib\Models\Builders\ShippingDetailsBuilder;
use PaypalServerSdkLib\Models\Builders\ShippingNameBuilder;
use PaypalServerSdkLib\Models\Builders\ShippingOptionBuilder;
use PaypalServerSdkLib\Models\ShippingType;
use PaypalServerSdkLib\Environment;
use PaypalServerSdkLib\Models\Builders\PaypalWalletBuilder;
use PaypalServerSdkLib\Models\Builders\PaypalWalletExperienceContextBuilder;
use PaypalServerSdkLib\Models\ShippingPreference;
use PaypalServerSdkLib\Models\PaypalExperienceLandingPage;
use PaypalServerSdkLib\Models\PaypalExperienceUserAction;
use PaypalServerSdkLib\Models\Builders\CallbackConfigurationBuilder;
use PaypalServerSdkLib\Models\Builders\PhoneNumberWithCountryCodeBuilder;
use PaypalServerSdkLib\Models\Builders\PaymentSourceBuilder;
use PaypalServerSdkLib\Models\CallbackEvents;

if(!defined('MYMUSE_ADMIN_PATH')){
	define('MYMUSE_ADMIN_PATH',JPATH_SITE.DS.'administrator'.DS.'components'.DS.'com_mymuse'.DS);
}
require_once( MYMUSE_ADMIN_PATH.DS.'helpers'.DS.'mymuse.php' );

/**
* MyMuse PaymentPaypal25 plugin
*
* @package 		MyMuse
* @subpackage	mymuse
*/
class plgMymusePayment_Paypal25 extends CMSPlugin 
{
	/**
	 * Load the language file on instantiation.
	 *
	 * @var    boolean
	 * @since  3.1
	 */
	protected $autoloadLanguage = true;

	/**
	 * Save the order_id
	 *
	 * @var    object
	 */
	protected $order_id = null;

	/**
	 * client
	 *
	 * @var    object
	 */
	protected $client = null;


	
	/**
	 * Constructor
	 *
	 * @param   object  $subject  The object to observe
	 * @param   array   $config   An array that holds the plugin configuration
	 */
	public function __construct(&$subject, $config)
	{
		$this->plgMyMusePayment_Paypal25($subject, $config);
	}
	
	function plgMyMusePayment_Paypal25(&$subject, $config)  {
		parent::__construct($subject, $config);
		
		if($this->params->get('my_paypal_sandbox'))
		{
			define('SANDBOX','true');
			putenv("UNIQID=$uniqid");
			define("PAYPAL_URL","https://api-m.sandbox.paypal.com");
			define("PAYPAL_CLIENT_ID", $this->params->get('my_paypal_sandbox_id'));
			define("PAYPAL_CLIENT_SECRET", $this->params->get('my_paypal_sandbox_secret_id'));
			$this->client = PaypalServerSdkClientBuilder::init()
		    ->clientCredentialsAuthCredentials(
		        ClientCredentialsAuthCredentialsBuilder::init(
		            PAYPAL_CLIENT_ID,
		            PAYPAL_CLIENT_SECRET
		        )
		    )
		    ->environment(Environment::SANDBOX)
		    ->build();
		}
		else
		{
			define('SANDBOX','false');
			define('PRODUCTION','true');
			define("PAYPAL_URL","https://api-m.paypal.com");
			define("PAYPAL_CLIENT_ID", $this->params->get('my_paypal_id'));
			define("PAYPAL_CLIENT_SECRET", $this->params->get('my_paypal_secret_id'));
			$this->client = PaypalServerSdkClientBuilder::init()
		    ->clientCredentialsAuthCredentials(
		        ClientCredentialsAuthCredentialsBuilder::init(
		            PAYPAL_CLIENT_ID,
		            PAYPAL_CLIENT_SECRET
		        )
		    )
		    ->environment(Environment::PRODUCTION)
		    ->build();
		}
		
	}

	/**
	 * Create an order to start the transaction.
	 * @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
	 */


	function createOrder($order)
	{
	    //global $client;
	    //print_pre($order); exit;
	    $items = '';
/*
	    for ($i=0;$i<$order->idx;$i++) {
	    	$items .= 'ItemBuilder::init(
	                        "'. $order->items[$i]->product_name.'",
	                        MoneyBuilder::init("'. $order->order_currency['currency_code'] .'", "'. $order->items[0]->product_item_price .'")->build(),
	                        "'. $order->items[$i]->product_quantity .'"
	                    )
	                        ->description("'.$order->items[$i]->product_name.'")
	                        ->sku("'.$order->items[$i]->product_sku.'")
	                        ->build(),
	                   ';

	     }
		 */
	    $orderBody = [
	        "body" => OrderRequestBuilder::init("CAPTURE", [
	            PurchaseUnitRequestBuilder::init(
	                AmountWithBreakdownBuilder::init($order->order_currency['currency_code'], $order->order_subtotal)
	                    ->breakdown(
	                        AmountBreakdownBuilder::init()
	                            ->itemTotal(
	                                MoneyBuilder::init($order->order_currency['currency_code'], $order->order_subtotal)->build()
	                            )
	                            ->build()
	                    )
	                    ->build()
	            )
	                // lookup item details in `cart` from database
	                ->items([




	                    ItemBuilder::init(
	                        $order->items[0]->product_name,
	                        MoneyBuilder::init($order->order_currency['currency_code'], $order->order_subtotal)->build(),
	                        "1"
	                    )
	                        ->description($order->items[0]->product_name)
	                        ->sku($order->items[0]->product_sku)
	                        ->build(),
	                




	                ])

	                ->build(),
	        ])
	        ->build(),
	    ];
	   

	    $apiResponse = $this->client->getOrdersController()->createOrder($orderBody);

	    return $this->handleResponse($apiResponse);

	}

	/**
	 * Capture payment for the created order to complete the transaction.
	 * @see https://developer.paypal.com/docs/api/orders/v2/#orders_capture
	 */

	function captureOrder($orderID)
	{

	    $captureBody = [
	        "id" => $orderID,
	    ];

	    $apiResponse = $this->client->getOrdersController()->captureOrder($captureBody);

	    return $this->handleResponse($apiResponse);
	}

	/**
	 * PayPal Payment form
	 * onBeforeMyMusePayment
	 */
	function onBeforeMyMusePayment($shopper, $store, $order, $params, $Itemid=1 )
	{

		$pp_order = $this->createOrder($order, $store);
		$pp_orderNumber = $pp_order['jsonResponse']['id'];
		//echo "orderNUmber = $pp_orderNumber";

		$path = Uri::root(true);
		$return = Uri::root().'index.php?option=com_mymuse&task=notify&order_id='.$order->id.'&payer_email='. $shopper->email .'&order_number='.$order->order_number.'&OrderID='.$pp_orderNumber;


		$sdkUrl = "https://www.paypal.com/sdk/js?client-id=";
		$sdkUrl .= PAYPAL_CLIENT_ID;

		if(SANDBOX == 'true'){
			$sdkUrl .= '&buyer-country=';
			$sdkUrl .= 'US';
		}
		
		$sdkUrl .= '&currency=';
		$sdkUrl .= $order->order_currency['currency_code'];
		$sdkUrl .= '&components=buttons&enable-funding=venmo,card';

		$string = '<style>
		div.mymuse_cart {
    border: none;
    padding: 5px;
    vertical-align: middle;
    height: 300px;
}
</style>
		
		
		
		<div id="paypal-button-container"></div>
       				<p id="result-message"></p>
			<!-- Initialize the JS-SDK -->

        	<script

            src="'.$sdkUrl.'"

            data-sdk-integration-source="developer-studio"

        ></script>

        <script>
        const paypalButtons = window.paypal.Buttons({
   style: {
        shape: "rect",
        layout: "vertical",
        color: "gold",
        label: "paypal",
    },
   message: {
        amount: '.sprintf("%.2f", $order->order_subtotal).',
    },

   async createOrder() {
        return "'.$pp_orderNumber.'";
    },
   async onApprove(data, actions) {
        try {
            const response = await fetch(
                `index.php?option=com_mymuse&task=notify&OrderID='.$pp_orderNumber.'&cmd=capture&order_id='.$order->id.'`,
                {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json",
                    },
                }
            );

            const orderData = await response.json();
            console.log("orderData");
            console.log(orderData);
            // Three cases to handle:
            //   (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
            //   (2) Other non-recoverable errors -> Show a failure message
            //   (3) Successful transaction -> Show confirmation or thank you message

            const errorDetail = orderData?.details?.[0];

            if (errorDetail?.issue === "INSTRUMENT_DECLINED") {
                // (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
                // recoverable state, per
                // https://developer.paypal.com/docs/checkout/standard/customize/handle-funding-failures/
                return actions.restart();
            } else if (errorDetail) {
                // (2) Other non-recoverable errors -> Show a failure message
                throw new Error(
                    `${errorDetail.description} (${orderData.debug_id})`
                );
            } else if (!orderData.purchase_units) {
                throw new Error(JSON.stringify(orderData));
            } else {
                // (3) Successful transaction -> Show confirmation or thank you message
                // Or go to another URL:  actions.redirect("thank_you.html");
                const transaction =
                    orderData?.purchase_units?.[0]?.payments?.captures?.[0] ||
                    orderData?.purchase_units?.[0]?.payments
                        ?.authorizations?.[0];
                resultMessage(
                    `Transaction ${transaction.status}: ${transaction.id}<br>
          			<br>Please wait a moment while we update our records!`
                );


                console.log(
                    "Capture result",
                    orderData,
                    JSON.stringify(orderData, null, 2)
                );

                window.location.href = "'.$return.'";

            }
        } catch (error) {
            console.error(error);
            resultMessage(
                `Sorry, your transaction could not be processed...<br><br>${error}`
            );
        }
    },

   
});
paypalButtons.render("#paypal-button-container");


// Example function to show a result to the user. Your sites UI library can be used instead.
function resultMessage(message) {
    const container = document.querySelector("#result-message");
    container.innerHTML = message;
}</script>

';

		return $string;
	}

	/**
	 * notify
	 * catch the IPN post from PayPal, return required responses, update orders and do mailouts
	 * 
	 */
	function onMyMuseNotify($params, $itemId = 1)
	{

		$app 	= Factory::getApplication();

		$date = date('Y-m-d h:i:s');
		$debug = "#####################\nPayPal notify PLUGIN\n";

		$result = array();
		$result['plugin'] 				= "payment_paypal";
		$result['myorder'] 				= 0; //must be >0 to trigger that it was this plugin
		$result['message_sent'] 		= 0; //must be >0 or tiggers error
		$result['message_received'] 	= 0; //must be >0 or tiggers error
		$result['order_found']			= 0; //must be >0 or tiggers error
		$result['order_verified'] 		= 0; //must be >0 or tiggers error
		$result['order_completed'] 		= 0; //must be >0 or tiggers error
		$result['order_number']			= 0; //must be >0 or tiggers error
		$result['order_id']				= 0; //must be >0 or tiggers error
		$result['payer_email']			= 0; 
		$result['payment_status']		= 0;
		$result['txn_id']				= 0;
		$result['error']				= '';


		//index.php?option=com_mymuse&task=notify&OrderID=${data.orderID}&cmd=capture

		if(!isset($_GET['OrderID'])){ 
			//wasn't paypal
			$debug .= "Was not PayPal. \n";
			$debug .= "-------END-------";
			if($params->get('my_debug')){
        		MymuseHelper::logMessage( $debug  );
  			}
  			return;
		}else{
			if($params->get('my_debug')){
				$debug .= "Get Input\n";
				$debug .= print_r($_GET, true);
        		MymuseHelper::logMessage( $debug  );
  			}
		}
		$OrderID = $_GET['OrderID'];
		$cmd = isset($_GET['cmd'])? isset($_GET['cmd']) : '';

		if($cmd == 'capture' ){

			
			header("Content-Type: application/json");

			   try {

			       $captureResponse = $this->captureOrder($OrderID);
			       $debug .= "Get Response\n";
			       if($params->get('my_debug')){
			       	$debug = print_r($captureResponse, true);
			           MymuseHelper::logMessage( $debug  );
			       }

			       echo json_encode($captureResponse["jsonResponse"]);

			   } catch (Exception $e) {

			       echo json_encode(["error" => $e->getMessage()]);
			       if($params->get('my_debug')){
			       	$debug = $e->getMessage();
			           MymuseHelper::logMessage( $debug  );
			       }

			       http_response_code(500);

			   }
			exit;		header("Content-Type: application/json");

		   try {

		       $captureResponse = $this->captureOrder($OrderID);
		       $debug .= "Get Response\n";
		       if($params->get('my_debug')){
		       	$debug = print_r($captureResponse, true);
		           MymuseHelper::logMessage( $debug  );
		       }

		       echo json_encode($captureResponse["jsonResponse"]);

		   } catch (Exception $e) {

		       echo json_encode(["error" => $e->getMessage()]);
		       if($params->get('my_debug')){
		       	$debug = $e->getMessage();
		           MymuseHelper::logMessage( $debug  );
		       }

		       http_response_code(500);

		   }
			exit;
		}

		$result['myorder'] = 1;
		$result['message_sent'] 		= 1; 
		$result['message_received'] 	= 1; 
		$result['order_found']			= 1; 
		$result['order_verified'] 		= 1; 
		$result['order_completed'] 		= 1; 
		$result['order_number']			= $_GET['order_number']; 
		$result['order_id']				= $_GET['order_id'];
		$result['payer_email']			= urldecode($_GET['payer_email']); 
		$result['payment_status']		= 'COMPLETED';
		$result['txn_id']				= $_GET['OrderID']; 
		$result['transaction_id']		= $_GET['OrderID']; 
		$result['transaction_status'] 	= 'COMPLETED';
		$result['redirect']				= Uri::root().'index.php?option=com_mymuse&task=thankyou&view=cart&pp=paypal&st=Completed&Itemid='.$itemId;

		$MymuseHelper = new MymuseHelper();
		$MymuseHelper->orderStatusUpdate($result['order_id'] , "C");
		
        return $result;

	}
	
	function onAfterMyMusePayment()
	{
		$email_msg = '';
		$good = 1;
		$input 		= Factory::getApplication()->input;
		$id 		= $input->get('id',0);
		if($id){
			$this->order_id = $id;
		}
		$ids = $this->params->get('product_ids');
		if($ids){
			$good = 0;
			$product_ids = explode(',', $ids);
			$db			= Factory::getContainer()->get('DatabaseDriver');
			$query = "SELECT * FROM `#__mymuse_order_item`
                    WHERE `order_id`='".$this->order_id."'";
        	$date = date('Y-m-d h:i:s');
        	$debug = "$date  onAfterMyMusePayment $query \n\n";
        	$debug .= "Product IDs".print_r($product_ids, true);
        		
        	$db->setQuery($query);
        	$items = $db->loadObjectList();
        	$debug .= "Items".print_r($items, true);
        	
  			foreach($items as $item){
  				if(in_array($item->product_id, $product_ids)){
  					$good = 1;
  				}
  			}
  			$debug .= "Good = $good \n\n";
		}
		

		if($good){
			if($this->params->get('email_msg')){
				$email_msg = "payment_paypal:".preg_replace("/\\n/","<br />",$this->params->get('email_msg'));
			}
		}
		if($this->params->get('my_debug')){
				$debug .= "onAfterMyMusePayment Email Message = $email_msg \n";
        		MymuseHelper::logMessage( $debug  );
  		}

		return $email_msg;
	
	}

	function handleResponse($response)
	{
	    $jsonResponse = json_decode($response->getBody(), true);
	    return [
	        "jsonResponse" => $jsonResponse,
	        "httpStatusCode" => $response->getStatusCode(),
	    ];
	}

}








