<?php
namespace Webkul\MpPayPal\Controller\Seller;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Customer\Model\Session;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\CsrfAwareActionInterface;
use Magento\Framework\App\Request\InvalidRequestException;

class CreateOrder extends Action implements CsrfAwareActionInterface
{
    protected $_publicActions = ['createorder'];

    /**
     * @var Magento\Customer\Model\Session
     */
    protected $_customerSession;

    /**
     * @var Webkul\Marketplace\Helper\Data
     */
    protected $_marketplaceHelper;

    /**
     * @var string
     */
    public $sellermail;

    /**
     * @var string
     */
    public $quoteId;

    /**
     * @param Context $context
     * @param Session $customerSession
     * @param \Magento\Checkout\Model\Session $checkoutSession
     * @param \Magento\Framework\Controller\Result\JsonFactory $jsonResultFactory
     * @param \Webkul\Marketplace\Helper\Data $marketplaceHelper
     * @param \Webkul\MpPayPal\Helper\Data $helper
     * @param \Magento\Framework\UrlInterface $url
     * @param \Webkul\MpPayPal\Model\PayPal\Adapter $adapter
     * @param \Webkul\MpPayPal\Gateway\Config\Config $modConfig
     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
     * @param \Magento\Framework\Json\Helper\Data $jsonHelper
     * @param \Magento\Catalog\Model\ProductFactory $productFactory
     * @param \Magento\Customer\Model\CustomerFactory $customerFactory
     */
    public function __construct(
        Context $context,
        Session $customerSession,
        \Magento\Checkout\Model\Session $checkoutSession,
        \Magento\Framework\Controller\Result\JsonFactory $jsonResultFactory,
        \Webkul\Marketplace\Helper\Data $marketplaceHelper,
        \Webkul\MpPayPal\Helper\Data $helper,
        \Magento\Framework\UrlInterface $url,
        \Webkul\MpPayPal\Model\PayPal\Adapter $adapter,
        \Webkul\MpPayPal\Gateway\Config\Config $modConfig,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Framework\Json\Helper\Data $jsonHelper,
        \Magento\Catalog\Model\ProductFactory $productFactory,
        \Magento\Quote\Model\ResourceModel\Quote\Item\CollectionFactory $quoteItemCollection,
        \Magento\Framework\Session\SessionManagerInterface $coreSession,
        \Magento\Customer\Model\CustomerFactory $customerFactory
    ) {
        parent::__construct($context);
        $this->_customerSession = $customerSession;
        $this->adapter = $adapter;
        $this->jsonResultFactory = $jsonResultFactory;
        $this->checkoutSession = $checkoutSession;
        $this->_marketplaceHelper = $marketplaceHelper;
        $this->helper = $helper;
        $this->jsonHelper = $jsonHelper;
        $this->url = $url;
        $this->modConfig = $modConfig;
        $this->storeManager = $storeManager;
        $this->productFactory = $productFactory;
        $this->customerFactory = $customerFactory;
        $this->coreSession = $coreSession;
        $this->quoteItemCollection = $quoteItemCollection;
    }

    public function createCsrfValidationException(RequestInterface $request): ?InvalidRequestException
    {
        return null;
    }

    public function validateForCsrf(RequestInterface $request): ?bool
    {
        return true;
    }

    public function execute()
    {
        $requestData = $this->getRequest()->getParams();
        $originalRequest = [];
        $originalRequest = $requestData;

        /**
         * purchase_units creationg
         */
        $originalRequest['intent'] = 'CAPTURE';
        $originalRequest['purchase_units'] = $this->createPurchaseUnit();
        $originalRequest['payer'] = $this->createPayerDetails();

        $originalRequest['application_context']['return_url'] = $this->url->getUrl('mppaypal/order/success');
        $originalRequest['application_context']['cancel_url'] = $this->url->getUrl('mppaypal/order/cancel');
        $originalRequest['application_context']["user_action"] = "PAY_NOW";
        $originalRequest['application_context']["shipping_preference"] = "NO_SHIPPING";
        $quote = $this->checkoutSession->getQuote();
        if (!empty($quote->getShippingAddress()->getShippingMethod())) {
            $originalRequest['application_context']["shipping_preference"] = "SET_PROVIDED_ADDRESS";
        }
        $this->helper->logDataInLogger(
            'request createOrder '.$this->jsonHelper->jsonEncode($originalRequest)
        );
        
        $returnData = $this->adapter->_create($originalRequest);
        $finalData = $this->jsonHelper->jsonDecode($returnData);
        $finalData['email_address'] = $this->sellermail;
        $finalData['quote_id'] = $this->quoteId;
        $resultJson = $this->jsonResultFactory->create();
        $this->helper->logDataInLogger('response createOrder '.$this->jsonHelper->jsonEncode($finalData));
        return $resultJson->setData($this->jsonHelper->jsonEncode($finalData));
    }

    /**
     * creates purchase units for relevent sellers
     *
     * @return array
     */
    public function createPurchaseUnit()
    {
        $request = [];
        /**
         * get data from quote
         */

        $quote = $this->checkoutSession->getQuote();
        $this->quoteId = $quote->getId();
        $finalCart = $this->helper->createFinalCart($quote);
        $this->coreSession->unsPayPalSellerData();
        $this->coreSession->setPayPalSellerData($finalCart);
        $i=0;
        $currencyCode = $this->storeManager->getStore()->getCurrentCurrencyCode();
        $shippingArray = [];
        foreach ($finalCart as $sellers) {
            $this->helper->logDataInLogger('response seller '.$this->jsonHelper->jsonEncode($sellers));
            if ($sellers['products'] && $sellers['seller']) {
                $onlyAdminShipping = false;
                $seller = $this->customerFactory->create()->load($sellers['seller']);
                $request[$i]['reference_id'] = 'PU_quoteId_'.$this->quoteId.'_sellerId_'.$sellers['seller'];
                $request[$i]['invoice_id'] = 'IN_'.$this->quoteId.'_'.$sellers['seller'];

                $request[$i]['payee']['merchant_id'] = $sellers['sub_merchant_id'];
                
                $this->sellermail = $seller->getEmail();
                $request[$i]['payment_instruction']['disbursement_mode'] = $this->modConfig
                ->getPaymentMode();
    
                $request[$i]['amount']['value'] = round(
                    $sellers['price'] - $sellers['discount'],
                    2
                );
                if (!$this->_marketplaceHelper->getConfigTaxManage()) {
                    $request[$i]['amount']['value'] += round($sellers['taxamount'], 2);
                }
                $request[$i]['amount']['currency_code'] = $currencyCode;
    
                /**
                 * breakdown definition
                 */
                $request[$i]['amount']['breakdown']['item_total']['currency_code'] = $currencyCode;
                $request[$i]['amount']['breakdown']['item_total']['value'] =
                round($sellers['price'] - $sellers['shippingprice'], 2);
                if ($this->_marketplaceHelper->getConfigTaxManage()) {
                    $request[$i]['amount']['breakdown']['item_total']['value'] -= round($sellers['taxamount'], 2);
                }
                $request[$i]['amount']['breakdown']['shipping']['currency_code'] = $currencyCode;
                $request[$i]['amount']['breakdown']['shipping']['value'] = round($sellers['shippingprice'], 2);
                $request[$i]['amount']['breakdown']['tax_total']['currency_code'] = $currencyCode;
                $request[$i]['amount']['breakdown']['tax_total']['value'] = round($sellers['taxamount'], 2);
                $request[$i]['amount']['breakdown']['discount']['value'] = round($sellers['discount'], 2);
                $request[$i]['amount']['breakdown']['discount']['currency_code'] = $currencyCode;
                $items = explode(',', $sellers['products']);
                $k = 0;
    
                $commission = round($sellers['commission'], 2);
                if (!$this->_marketplaceHelper->getConfigTaxManage()) {
                    $commission += round($sellers['taxamount'], 2);
                }
                $request[$i]['payment_instruction']['platform_fees'][$k]['amount']
                ['value'] = round($commission, 2);
                $request[$i]['payment_instruction']['platform_fees'][$k]['amount']
                ['currency_code'] = $currencyCode;
                $request[$i]['payment_instruction']['platform_fees'][$k]['payee']
                ['merchant_id'] = $this->modConfig->getPartnerMerchantId();
                
                foreach ($items as $item) {
                    /**
                     * add items to bucket
                     */
                    $quoteItemData = $this->quoteItemCollection->create()
                    ->addFieldToFilter('quote_id', $this->quoteId)
                    ->addFieldToFilter('product_id', $item)->getFirstItem();
                    $product = $this->productFactory->create()->load($item);
                    $request[$i]['items'][$k]['name'] = $product->getName();
                    $request[$i]['items'][$k]['sku'] = $product->getSku();
                    $request[$i]['items'][$k]['quantity'] = $sellers['qty'];
                    $request[$i]['items'][$k]['unit_amount']['currency_code'] = $currencyCode;
                    $request[$i]['items'][$k]['unit_amount']['value'] = round($quoteItemData->getPrice(), 2);
                    $k++;
                }
    
                /**
                 * manage shipping address
                 */
                if (!empty($quote->getShippingAddress()->getShippingMethod())) {
                    $request[$i]['shipping']['shipping_method'] = $quote->getShippingAddress()->getShippingMethod();
                    $request[$i]['shipping']['address']['address_line_1'] = implode(
                        ',',
                        $quote->getShippingAddress()->getStreet()
                    );
                    $request[$i]['shipping']['address']['address_line_2'] = $quote->getShippingAddress()->getCity();
                    $request[$i]['shipping']['address']['country_code'] = $quote->getShippingAddress()->getCountryId();
                    $request[$i]['shipping']['address']['postal_code'] = $quote->getShippingAddress()->getPostcode();
                    $request[$i]['shipping']['address']['admin_area_2'] = $quote->getShippingAddress()->getCity();
                    $request[$i]['shipping']['address']['admin_area_1'] = $quote->getShippingAddress()->getCity();
                }
            } else {
                $shippingArray = $sellers;
            }
            $i++;
        }
        if (!empty($shippingArray)) {
            $request = $this->manageShipping($request, $shippingArray);
        }
        return $request;
    }

    /**
     * add shipping to comission and purchase units
     *
     * @param array $request
     * @param array $shippingArray
     * @return array
     */
    public function manageShipping($request, $shippingArray)
    {
        $sellersCount = count($request);
        $eachSellerShipping = round($shippingArray['price']/$sellersCount, 2);
        $finalArray = [];
        $i = 0;
        foreach ($request as $purchaseUnit) {
            $finalArray[$i] = $purchaseUnit;
            $finalArray[$i]['payment_instruction']['platform_fees'][0]['amount']['value'] += $eachSellerShipping;
            $finalArray[$i]['amount']['value'] += $eachSellerShipping;
            $finalArray[$i]['amount']['breakdown']['shipping']['value'] += $eachSellerShipping;
            $i++;
        }
        return $finalArray;
    }

    /**
     * generate payer details
     *
     * @return array
     */
    public function createPayerDetails()
    {
        $quote = $this->checkoutSession->getQuote();
        $shippingAddress = $quote->getShippingAddress();
        $billingAddress = $quote->getBillingAddress();
        if (!$shippingAddress->getCountryId()) {
            $shippingAddress = $quote->getBillingAddress();
        }
        $payerData = [];
        $customer = $quote->getCustomer();
        if (!$this->_customerSession->isLoggedIn()) {
            $this->helper->setGuestQuote($quote);
        }
        $payerData['name']['given_name'] = $billingAddress->getData('firstname');
        $payerData['name']['surname'] = $billingAddress->getData('lastname');
        $payerData['email_address'] = $quote->getCustomerEmail();
        $payerData['address']['address_line_1'] = implode(
            ',',
            $shippingAddress->getStreet()
        );
        $payerData['address']['address_line_2'] = $shippingAddress->getCity();
        $payerData['address']['country_code'] = $shippingAddress->getCountryId();
        $payerData['address']['postal_code'] = $shippingAddress->getPostcode();
        $payerData['address']['admin_area_2'] = $shippingAddress->getCity();
        $payerData['address']['admin_area_1'] = $shippingAddress->getCity();
        return $payerData;
    }
}
