<?php

namespace Magento\Billdesk\Model;

require dirname(__FILE__, 2) . '/' . 'vendor/autoload.php';
//require_once(__DIR__ . '/../../vendor/autoload.php');

use io\billdesk\client\hmacsha256\BillDeskJWEHS256Client;
use io\billdesk\client\hmacsha256\JWESymmetricHelper;
use io\billdesk\client\hmacsha256\Config as BilldeskClientConfig;
use Exception;
use Magento\Framework\Exception\LocalizedException;
use Magento\Sales\Model\ResourceModel\Order\Payment\Transaction\CollectionFactory as TransactionCollectionFactory;
use Magento\Payment\Model\InfoInterface;
use Magento\Billdesk\Model\Config as MagentoConfig;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Magento\Framework\App\ObjectManager;
use io\billdesk\client\hmacsha256\JWEHS256Helper;
use GuzzleHttp\Psr7\Message;
use Magento\Framework\Pricing\Render\Amount;

class PaymentMethod extends \Magento\Payment\Model\Method\AbstractMethod
{
    const CHANNEL_NAME                  = 'Magento';
    const METHOD_CODE                   = 'billdesk';
    const CURRENCY                      = 'INR';


    protected $_code                    = self::METHOD_CODE;
    protected $_canAuthorize            = true;
    protected $_canCapture              = true;
    protected $_canRefund               = true;
    protected $_canUseInternal          = false;
    protected $_canUseCheckout          = true;
    protected $_canRefundInvoicePartial = true;
    protected $requestMaskedFields      = null;

    protected $config;
    protected $request;
    protected $salesTransactionCollectionFactory;
    protected $productMetaData;
    protected $regionFactory;
    protected $orderRepository;
    protected $signingKey;
    protected $encryptionKey;
    protected $client_id;
    protected $key_id;
    protected $merchant_id;

    public function __construct(
        \Magento\Framework\Model\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory,
        \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory,
        \Magento\Payment\Helper\Data $paymentData,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        \Magento\Payment\Model\Method\Logger $logger,
    //  \Magento\Billdesk\Model\Config $config,
         MagentoConfig $config,
        \Magento\Framework\App\RequestInterface $request,
        \Magento\Framework\App\ProductMetadataInterface $productMetaData,
        \Magento\Directory\Model\RegionFactory $regionFactory,
        \Magento\Sales\Api\OrderRepositoryInterface $orderRepository,
        \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
        \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
        array $data = []
    ) {
        parent::__construct(
            $context,
            $registry,
            $extensionFactory,
            $customAttributeFactory,
            $paymentData,
            $scopeConfig,
            $logger,
            $resource,
            $resourceCollection,
            $data
        );
        $this->config = $config;
        $this->request = $request;
        $this->productMetaData = $productMetaData;
        $this->regionFactory = $regionFactory;
        $this->orderRepository = $orderRepository;
        $this->client_id = $this->config->getConfigData(Config::CLIENT_ID);
        $this->key_id = $this->config->getConfigData(Config::KEY_ID);
        $this->merchant_id = $this->config->getConfigData(Config::MERCHANT_ID);
        $this->signingKey = $this->config->getConfigData(Config::JOSE_SIGNING_KEY);
        $this->encryptionKey = $this->config->getConfigData(Config::JOSE_ENCRYPTION_KEY);   
       // $this->merchant_key = $this->config->getConfigData(Config::MERCHANT_KEY);
        $this->_directory = ObjectManager::getInstance()->get('\Magento\Framework\Filesystem\DirectoryList');
    }

    /**
     * Validate data
     *
     * @return $this
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function validate()
    {
        $info = $this->getInfoInstance();
        if ($info instanceof \Magento\Sales\Model\Order\Payment) {
            $billingCountry = $info->getOrder()->getBillingAddress()->getCountryId();
        } else {
            $billingCountry = $info->getQuote()->getBillingAddress()->getCountryId();
        }

        if (!$this->config->canUseForCountry($billingCountry)) {
            throw new LocalizedException(__('Selected payment type is not allowed for billing country.'));
        }

        return $this;
    }

    /**
     * Authorizes specified amount
     *
     * @param InfoInterface $payment
     * @param string $amount
     * @return $this
     * @throws LocalizedException
     */
    public function authorize(InfoInterface $payment, $amount)
    {
        $log = new Logger('name');
        //$log->pushHandler(new StreamHandler($this->_directory->getPath('log') . '/BillDesk/magento_billdesk_' . Date('Y_m_d') . '.log'));
        $logDir = $this->_directory->getPath('log') . '/BillDesk';
        if (!is_dir($logDir)) {
            mkdir($logDir, 0775, true);
        }
        $logFile = $logDir . '/magento_billdesk_' . date('Y_m_d') . '.log';
        $log->pushHandler(new StreamHandler($logFile));
        try {
            $config = $this->config;
            //$merchant_key    = $config->getConfigData($config::MERCHANT_KEY);
            $client_id        = $config->getConfigData($config::CLIENT_ID);
            $key_id        = $config->getConfigData($config::KEY_ID);

            $transaction_response = (isset($_POST['transaction_response'])) ? $_POST['transaction_response'] : null;

           // $client = new JWEHS256Helper($merchant_key, $client_id);
           $client = new JWESymmetricHelper(
                            $this->encryptionKey,
                            $client_id,
                            $key_id,
                            $log,
                            $this->signingKey,
                            "AES_DIR"
                        );
                    if (empty($transaction_response)) {
                        $log->error('Missing transaction_response in request');
                        throw new \Exception('transaction_response is empty');
                    }

                    $log->debug('Raw transaction_response: ' . $transaction_response);

            $jws = $client->verifyAndDecrypt($transaction_response);
            if (!$jws) {
                        $log->error('verifyAndDecrypt returned empty or null');
                        throw new \Exception('Decryption failed');
                    }

                    $log->debug('Decrypted JWS payload: ' . $jws);
            $txn = json_decode($jws, false); 
            $log->info('Parsed transaction object:', ['txn' => $txn]);
            $log->info('Parsed transaction object associative array:', ['txn_array' => (array) $txn]);
            $order = $payment->getOrder();
            $orderId = $order->getIncrementId();
            //$request = $this->getPostData();
            $request = $this->request->getPostValue();
            $payment->setStatus(self::STATUS_APPROVED)
                ->setAmountPaid($amount)
                ->setLastTransId($txn->transactionid)
                ->setTransactionId($txn->transactionid)
                ->setIsTransactionClosed(true)
                ->setShouldCloseParentTransaction(true);
        } catch (\Exception $e) {
            //$log->error("BillDesk Error In authorize amount: " . [$e->getMessage()]);
            $log->error("BillDesk Error In authorize amount: " . $e->getMessage());
            throw new LocalizedException(__('BillDesk Error In authorize amount: %1.', $e->getMessage()));
        }
        return $this;
    }

    public function capture(InfoInterface $payment, $amount)
    {
        $log = new Logger('name');
        //$log->pushHandler(new StreamHandler($this->_directory->getPath('log') . '/BillDesk/magento_billdesk_' . Date('Y_m_d') . '.log'));
        $logDir = $this->_directory->getPath('log') . '/BillDesk';
            if (!is_dir($logDir)) {
                mkdir($logDir, 0775, true);
            }
            $logFile = $logDir . '/magento_billdesk_' . date('Y_m_d') . '.log';
            $log->pushHandler(new StreamHandler($logFile));
        //check if payment has been authorized
        if (is_null($payment->getParentTransactionId())) {
            $this->authorize($payment, $amount);
        }

        return $this;
    }
    /**
     * Refunds specified amount
     *
     * @param InfoInterface $payment
     * @param float $amount
     * @return $this
     * @throws LocalizedException
     */

    public function refund(InfoInterface $payment, $amount)
    {
        $log = new Logger('name');
        //$log->pushHandler(new StreamHandler($this->_directory->getPath('log') . '/BillDesk/magento_billdesk_' . Date('Y_m_d') . '.log'));
        $logDir = $this->_directory->getPath('log') . '/BillDesk';
        if (!is_dir($logDir)) {
            mkdir($logDir, 0775, true);
        }
        $logFile = $logDir . '/magento_billdesk_' . date('Y_m_d') . '.log';
        $log->pushHandler(new StreamHandler($logFile));
        $transaction_response = (isset($_POST['transaction_response'])) ? $_POST['transaction_response'] : null;
        $order = $payment->getOrder();
        $creditmemo = $this->request->getPost('creditmemo');
        $reason = (!empty($creditmemo['comment_text'])) ? $creditmemo['comment_text'] : 'Refunded by site admin';
        $refundId = $payment->getTransactionId();
        $paymentId = substr($refundId, 0, -7);
        try {

            $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
            $resource = $objectManager->get('Magento\Framework\App\ResourceConnection');
            $connection = $resource->getConnection();
            $tableName = $resource->getTableName('billdesk_payment_transation');

            $sql = "Select orderid,transaction_date,charge_amount,currency from " . $tableName . " where transactionid = '" . $paymentId . "'   ";
            $result = $connection->fetchAll($sql);
            $orderid = '';
            $transaction_date = '';
            $charge_amount = '';
            $currency = '';

            foreach ($result as $values) {
                $orderid = $values['orderid'];
                $transaction_date = $values['transaction_date'];
                $charge_amount = $values['charge_amount'];
                $currency = $values['currency'];
            }

            $config = $this->config;
            //$merchant_key    = $config->getConfigData($config::MERCHANT_KEY);
            
            $client_id     = $config->getConfigData($config::CLIENT_ID);
            $key_id     = $config->getConfigData($config::KEY_ID);
            $merchant_id   = $config->getConfigData($config::MERCHANT_ID);
            $itemcode      = $config->getConfigData($config::ITEM_CODE);
            $child_window  = $config->getConfigData($config::CHILD_WINDOW);
            $signingKey    = $config->getConfigData($config::JOSE_SIGNING_KEY);
            $encryptionKey = $config->getConfigData($config::JOSE_ENCRYPTION_KEY);
            $env           = $config->getConfigData($config::ENV_VARIABLE);

            $refundid = '';
            $order = '';
            $baseUrl = ($env == "UAT") ? 'https://uat1.billdesk.com/u2' : 'https://api.billdesk.com';

            $clientConfig = new BilldeskClientConfig();
            $clientConfig->setMerchantId($merchant_id);
            $clientConfig->setClientId($client_id);
            $clientConfig->setEncryptionKeyBase64($encryptionKey);
            $clientConfig->setSigningKeyBase64($signingKey);
            $clientConfig->setEncryptionKeyId($key_id);
            $clientConfig->setSigningKeyId("AES_DIR");

           /*  if ($env == "UAT") {
             //   $client = new BillDeskJWEHS256Client('https://uat1.billdesk.com/u2', $client_id, $merchant_key);
            } else {
              //  $client = new BillDeskJWEHS256Client('https://pgapi.billdesk.com', $client_id, $merchant_key);
            } */
            $client = new BillDeskJWEHS256Client($clientConfig, $baseUrl);
            $client->setLogger($log);
            $request = array(
                'transactionid' => $paymentId,
                'orderid' => $orderid,
                'mercid' => $merchant_id,
                'transaction_date' => $transaction_date,
                'txn_amount' => $charge_amount,
                'refund_amount' => $amount,
                'currency' => $currency,
                'merc_refund_ref_no' => uniqid()
            );
            $response = $client->refundTransaction($request);
            $results = $response->getResponse();
            $log->info("BillDesk Refund function response: ", array($response));
            $log->info("BillDesk Refund function results: ", array($results));
            if (isset($results->status)) {
                if ($results->status == '403' || $results->status == '401') {
                    throw new LocalizedException(__("$results->message"));
                }
            } else {
                $payment->setAmountPaid($amount)
                    ->setLastTransId($results->refundid)
                    ->setTransactionId($results->refundid)
                    ->setIsTransactionClosed(true)
                    ->setShouldCloseParentTransaction(true);
            }
        } catch (\Exception $e) {
            //$log->error("BillDesk Error In Refund function: %1.", array($e->getMessage()));
            $log->error("BillDesk Error In Refund function: " . $e->getMessage());

            throw new LocalizedException(__('BillDesk Error: %1.', $e->getMessage()));
        }
        return $this;
    }

    /**
     * Format param "channel" for transaction
     *
     * @return string
     */
    protected function getChannel()
    {
        $edition = $this->productMetaData->getEdition();
        $version = $this->productMetaData->getVersion();
        return self::CHANNEL_NAME . ' ' . $edition . ' ' . $version;
    }
}
