<?php
namespace TbiBank\FusionPay\Controller\Api;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Quote\Model\QuoteManagement;
use Magento\Quote\Model\QuoteFactory;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Quote\Model\Quote\AddressFactory;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\CsrfAwareActionInterface;
use Magento\Framework\App\Request\InvalidRequestException;
use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Api\OrderRepositoryInterface;

use TbiBank\FusionPay\Model\Cryptor;
use TbiBank\FusionPay\Model\ProgrammaticOrderContext;
use TbiBank\FusionPay\Helper\Data as FusionPayHelper;
use TbiBank\FusionPay\Model\TbiStatusUpdate;
use TbiBank\FusionPay\Logger\FusionPayLogger;

class Gateway extends Action implements CsrfAwareActionInterface
{
    protected $resultJsonFactory;
    protected $fusionPayHelper;
    protected $cryptor;
    protected $storeManager;
    protected $quoteManagement;
    protected $quoteFactory;
    protected $productRepository;
    protected $customerRepository;
    protected $addressFactory;
    protected $orderRepository;
    protected $programmaticOrderContext;
    protected $tbiStatusUpdate;
    protected $fusionPayLogger;

    public function __construct(
        Context $context,
        JsonFactory $resultJsonFactory,
        FusionPayHelper $fusionPayHelper,
        Cryptor $cryptor,
        StoreManagerInterface $storeManager,
        QuoteManagement $quoteManagement,
        QuoteFactory $quoteFactory,
        ProductRepositoryInterface $productRepository,
        CustomerRepositoryInterface $customerRepository,
        AddressFactory $addressFactory,
        OrderRepositoryInterface $orderRepository,
        ProgrammaticOrderContext $programmaticOrderContext,
        TbiStatusUpdate $tbiStatusUpdate,
        FusionPayLogger $fusionPayLogger
    ) {
        parent::__construct($context);
        $this->resultJsonFactory = $resultJsonFactory;
        $this->fusionPayHelper = $fusionPayHelper;
        $this->cryptor = $cryptor;
        $this->storeManager = $storeManager;
        $this->quoteManagement = $quoteManagement;
        $this->quoteFactory = $quoteFactory;
        $this->productRepository = $productRepository;
        $this->customerRepository = $customerRepository;
        $this->addressFactory = $addressFactory;
        $this->orderRepository = $orderRepository;
        $this->programmaticOrderContext = $programmaticOrderContext;
        $this->tbiStatusUpdate = $tbiStatusUpdate;
        $this->fusionPayLogger = $fusionPayLogger;
    }

    /**
     * Execute method
     *
     * @return \Magento\Framework\Controller\Result\Json
     */
    public function execute()
    {
        $this->fusionPayLogger->info('FusionPay: Gateway Request');
        $resultJson = $this->resultJsonFactory->create();
        $encryptionKey = $this->fusionPayHelper->getConfigValue('tbi_settings/general_settings/encryption_key');
        $request = $this->getRequest();

        $allowedOrigin = $this->fusionPayHelper->getConstValue('TBI_PLATFORM_URL');
        $allowedIP = $this->fusionPayHelper->getConstValue('ALLOWED_IP');
        
        // Check for the allowed IP address
        $clientIp = $request->getClientIp();
        // Check for the allowed origin
        $origin = $request->getHeader('Origin');
        //$this->fusionPayLogger->info('FusionPay: Gateway Request Content: ' . $request->getContent()) ;
        //$this->fusionPayLogger->info('FusionPay: Gateway Request Origin: ' . $origin) ;

        // Check if the request is POST
        if (!$request->isPost()) {
            $this->fusionPayLogger->info('FusionPay: Gateway Request: NOT A POST REQUEST');
            return $this->resultJsonFactory->create()->setData([
                'error' => 1,
                'message' => 'Access denied.'
            ]);
        }


        // if ($origin !== $allowedOrigin) {
        //     $this->fusionPayLogger->info('FusionPay: Gateway Request THE ORIGIN IS NOT ALLOWED');
        //     return $this->resultJsonFactory->create()->setData([
        //         'error' => 1,
        //         'message' => 'Access denied.'
        //     ]);
        // }


        // if ($clientIp !== $allowedIP) {
        //     $this->fusionPayLogger->info('FusionPay: Gateway Request THE IP IS NOT ALLOWED: ' . $clientIp . " AND " . $allowedIP);
        //     return $this->resultJsonFactory->create()->setData([
        //         'error' => 1,
        //         'message' => 'Access denied.'
        //     ]);
        // }

        try {
            // Retrieve JSON data from the request body
            $jsonContent = $request->getContent();
            $requestData = json_decode($jsonContent, true);
    
            // Validate and sanitize the input
            if (!isset($requestData['data'])) {
                $this->fusionPayLogger->info('FusionPay: Gateway Request THERE IS NO DATA');
                return $this->resultJsonFactory->create()->setData([
                    'error' => 1,
                    'message' => 'Access denied.'
                ]);
            }
            $encryptedData = htmlspecialchars($requestData['data']);
    
            // Decrypt the data
            $decryptedData = $this->cryptor->Decrypt($encryptedData, $encryptionKey);
    
            $decodedData = (array) json_decode($decryptedData);
            
            //$this->fusionPayLogger->info('FusionPay RO:' . $decodedData['order_id'] . $decodedData['command'] . $decodedData['status']);

            if(isset($decodedData['command']) && isset($decodedData['order_id']) && isset($decodedData['status']) && $decodedData['command']=='update_status' ) {

                switch ($decodedData['status']) {        			
            		case '0' : 
            			$tbi_status =  __( "Canceled" );
            			break; 
                    case '1' : 
                        $tbi_status =  __( "Approved" );
                        break;
                    case '2' : 
                        $tbi_status =  __( "In Progress" );
                        break;  
            		case '3' : 
            			$tbi_status =  __( "Rejected" );
            			break;
            		default :
            			$tbi_status =  __( "Draft" );
            			break;
            	}

                    $contractId = null;
                    if (isset($decodedData['contract_id']) && $decodedData['contract_id'] !== '') {
                        $contractId = (string) $decodedData['contract_id'];
                    }

                    $this->tbiStatusUpdate->updateStatus($decodedData['order_id'], $tbi_status, $contractId);
                return $resultJson->setData([
                    'success'   =>    true,
                    'order_id'  =>   $decodedData['order_id']
                ]);
            }



            if(isset($decodedData['command']) && $decodedData['command'] == 'create_order'){
                $this->fusionPayLogger->info('FusionPay: Gateway Request create order');

                $customerEmail = $decodedData['email'];
                $customerFirstName = $decodedData['firstname'];
                $customerLastName = $decodedData['lastname'];

                // Initialize Quote
                $quote = $this->quoteFactory->create();
                if (!$quote) {
                    throw new \Exception("Failed to create a new quote.");
                }
                $store = $this->storeManager->getStore();
                if (!$store) {
                    throw new \Exception("Failed to create a new storeManager.");
                }
                $quote->setStore($store);
                $quote->setCurrency();
                $quote->save();

                if(!$quote->getId()) {
                    throw new \Exception("Failed to getquote.");
                }

                // Set Customer (assuming guest customer)
                $quote->setCustomerEmail($customerEmail);
                $quote->setCustomerIsGuest(true);
                $quote->setCustomerFirstname($customerFirstName);
                $quote->setCustomerLastname($customerLastName);

                $item = $decodedData['items'][0]; // Directly accessing the first item

                $productId = $item->params->product; // ID of the product
                $qty = intval($item->qty); // Quantity of the product, ensuring it's an integer
                
                // Retrieve the product by ID
                $product = $this->productRepository->getById($productId);

                // Prepare a data object for adding the product to the quote
                $request = new \Magento\Framework\DataObject();
                $requestData = [
                    'product' => $productId,
                    'qty' => $qty
                ];

                // Check for configurable options
                if (isset($item->params->super_attribute) && !empty($item->params->super_attribute)) {
                    $requestData['super_attribute'] = (array) $item->params->super_attribute; // Ensure this is an array
                }

                // Check for custom options
                if (isset($item->params->options) && !empty($item->params->options)) {
                    $requestData['options'] = (array) $item->params->options; // Cast to array if necessary
                }

                // Add any other necessary parameters
                if (!empty($item->params->selected_configurable_option)) {
                    $requestData['selected_configurable_option'] = $item->params->selected_configurable_option;
                }

                if (!empty($item->params->related_product)) {
                    $requestData['related_product'] = $item->params->related_product;
                }

                $request->setData($requestData);

                // Add product to the quote with the provided data
                $quote->addProduct($product, $request);

                // Set Billing and Shipping Addresses
                $addressData = [
                    'firstname' => $customerFirstName,
                    'lastname' => $customerLastName,
                    'street' => $decodedData['deliveryaddress']->streetname,
                    'city' => $decodedData['deliveryaddress']->city,
                    'postcode' => $decodedData['deliveryaddress']->postalcode,
                    'telephone' => $decodedData['phone'],
                    'country_id' => 'RO'
                    // Add other address fields as necessary
                ];
                // You may need to adjust the logic here to ensure that removing 'region_id' doesn't cause issues
                $billingAddress = $this->addressFactory->create()->addData($addressData);
                $shippingAddress = $this->addressFactory->create()->addData($addressData);

                $quote->setBillingAddress($billingAddress);
                $quote->setShippingAddress($shippingAddress);

                // Set Shipping Method (assuming a valid method code)
                $shippingMethod = 'flatrate_flatrate';
                $quote->getShippingAddress()->setCollectShippingRates(true)
                    ->collectShippingRates()
                    ->setShippingMethod($shippingMethod);
                    
                // Before setting the payment method, ensure the quote is not null and properly loaded
                if (!$quote || !$quote->getId()) {
                    throw new \Exception("Quote is not properly initialized.");
                }



                // Collect Totals and Save Quote
                $quote->collectTotals()->save();

                $this->programmaticOrderContext->activate();

                // Set Payment Method
                $quote->getPayment()->importData(['method' => 'fusionpay']);

                // Convert Quote to Order
                $order = $this->quoteManagement->submit($quote);

                $tbi_status = __( "In Progress" );
                
                // Save the order to persist the changes
                $this->orderRepository->save($order);

                $this->tbiStatusUpdate->updateStatus($order->getIncrementId(), $tbi_status);

                // Additional order processing (e.g., sending email)
                // $this->fusionPayLogger->info('Order created successfully (increment): ' . $order->getIncrementId());
                // $this->fusionPayLogger->info('Order created successfully (id): ' . $order->getId());
                return $resultJson->setData([
                    'success' => true,
                    'order_id' => $order->getIncrementId()
                ]);
            }
    
        } catch (\Exception $e) {
            // Handle any exceptions and return an error response
            return $resultJson->setData([
                'error' => 1,
                'message' => $e->getMessage()
            ]);
        }
    }

    /**
     * Bypass CSRF check
     *
     * @param RequestInterface $request
     * @return null|InvalidRequestException
     */
    public function createCsrfValidationException(RequestInterface $request): ?InvalidRequestException
    {
        return null;
    }

    /**
     * Bypass CSRF check
     *
     * @param RequestInterface $request
     * @return bool
     */
    public function validateForCsrf(RequestInterface $request): ?bool
    {
        return true;
    }
}
