<?php
namespace Extension\DataCapture;

use Application\Config;
use Application\CrmPayload;
use Application\CrmResponse;
use Application\Helper\Provider;
use Application\Helper\Security;
use Application\Http;
use Application\Logger;
use Application\Model\Configuration;
use Application\Registry;
use Application\Request;
use Application\Session;
use DateTime;
use Exception;

class DataCapture
{
    protected $authKey, $pageType;
    public function __construct()
    {
        $this->currentStepId      = (int) Session::get('steps.current.id');
        $this->previousStepId     = (int) Session::get('steps.previous.id');
        $this->pageType           = Session::get('steps.current.pageType');
        $this->authKey            = Registry::system('systemConstants.LEGACY_AUTH_KEY');
        $this->enableLocalCapture = Config::extensionsConfig('DataCapture.enable_local_capture');
        $this->tableName          = Config::extensionsConfig('DataCapture.local_data_table');
        $this->domainName         = Provider::removeSubDomain(trim(Request::getHttpHost(), '/'));
        $this->date               = date('MY');
        $this->secureKey          = md5($this->domainName . $this->date);
        $this->currentConfigId    = Session::get('steps.current.configId');
    }
    public function checkExtensionStatus($extensionName)
    {
        $extensions        = Config::extensions();
        $isExtensionActive = false;
        if (!empty($extensions)) {
            foreach ($extensions as $extension) {
                if ($extension['extension_slug'] == $extensionName) {
                    $isExtensionActive = $extension['active'];
                    break;
                }
            }
        }
        return $isExtensionActive;
    }
    public function activate()
    {
        $remoteURL         = Registry::system('systemConstants.LEGACY_URL');
        $gatewaySwitcherId = Config::settings('gateway_switcher_id', $this->currentConfigId);
        $encryptionKey     = Config::settings('encryption_key', $this->currentConfigId);
        $dataDestination   = Config::extensionsConfig('DataCapture.data_destination');
        if (in_array('local', $dataDestination) && count($dataDestination) == 1) {
            return true;
        }
        if (empty($remoteURL)) {
            throw new Exception(
                'Remote URL is missing. Please check your settings.'
            );
        }
        if (empty($gatewaySwitcherId)) {
            throw new Exception(
                'Instance ID is missing. Please check your settings.'
            );
        }
        if (empty($encryptionKey)) {
            throw new Exception(
                'Encryption key is missing. Please check your settings.'
            );
        }
        return true;
    }
    public function checkDbCredentials()
    {
        //Strict version check for fallback major update
        if ($this->isOldFrameworkVersion(14)) {
            throw new Exception("Please update the framework to make it compatible with this extension version and then try to resave this. !!");
        }
        $remoteURL         = Registry::system('systemConstants.LEGACY_URL');
        $gatewaySwitcherId = Config::settings('gateway_switcher_id', $this->currentConfigId);
        $encryptionKey     = Config::settings('encryption_key', $this->currentConfigId);
        $dataDestination   = Request::form()->get('data_destination');
        if (in_array('external', $dataDestination)) {
            if (empty($remoteURL)) {
                throw new Exception(
                    'Remote URL is missing. Please check your settings.'
                );
            }
            if (empty($gatewaySwitcherId)) {
                throw new Exception(
                    'Instance ID is missing. Please check your settings.'
                );
            }
            if (empty($encryptionKey)) {
                throw new Exception(
                    'Encryption key is missing. Please check your settings.'
                );
            }
        }
        if (in_array('local', $dataDestination)) {
            $dbHost     = Config::settings('db_host');
            $dbUsername = Config::settings('db_username');
            $dbPassword = Config::settings('db_password');
            $dbName     = Config::settings('db_name');
            if (
                empty($dbHost) ||
                empty($dbUsername) ||
                empty($dbName)
            ) {
                throw new Exception(
                    'Db credentials are missing. Please check your settings.'
                );
            }
            if (!extension_loaded('pdo_mysql')) {
                throw new Exception("Mysql PDO extension is not installed.");
            }
            $tableName    = 'local_data_unify_' . Helper::cleanString(Request::getOfferPath());
            $dbConnection = Helper::getDatabaseConnection();
            $dbName       = Config::settings('db_name');
            $checkTable   = "SELECT * FROM `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`='$dbName' AND `TABLE_NAME`='$tableName'";
            try {
                $isTable = $dbConnection->fetchAll($checkTable);
            } catch (Exception $ex) {
            }
            $funnelID = Request::form()->get('funnel_id');
            if (empty($isTable[0]['TABLE_NAME'])) {
                $tableName = 'local_data_unify_' . $funnelID;
            }
            self::createTable($tableName);
        }
        Request::form()->set('local_data_table', $tableName);
        return true;
    }
    public function captureCrmPayload()
    {
        if (
            (Request::attributes()->get('action') == 'prospect' &&
                Config::extensionsConfig('DataCapture.data_capture_types') != "prospect" &&
                Config::extensionsConfig('DataCapture.data_capture_types') != "prospect_checkout_upsell_downsell"
            ) ||
            (Request::attributes()->get('action') == 'checkout' &&
                Config::extensionsConfig('DataCapture.data_capture_types') != "checkout_upsell_downsell" &&
                Config::extensionsConfig('DataCapture.data_capture_types') != "prospect_checkout_upsell_downsell"
            ) ||
            (Request::attributes()->get('action') == 'upsell' &&
                Config::extensionsConfig('DataCapture.data_capture_types') != "checkout_upsell_downsell" &&
                Config::extensionsConfig('DataCapture.data_capture_types') != "prospect_checkout_upsell_downsell"
            ) ||
            (Request::attributes()->get('action') == 'downsell' &&
                Config::extensionsConfig('DataCapture.data_capture_types') != "checkout_upsell_downsell" &&
                Config::extensionsConfig('DataCapture.data_capture_types') != "prospect_checkout_upsell_downsell"
            )
        ) {
            return;
        }
        if (Session::get('extensions.dataCapture') && $this->currentStepId != 1) {
            return;
        }
        $prospectPayload = false;
        if (empty(Session::get('extensions.dataCapture.prospectPayLoad')) &&
            Request::attributes()->get('action') == 'prospect') {
            $prospectPayload = CrmPayload::all();
        }
        $configuration          = new Configuration(CrmPayload::get('meta.configId'));
        $isDelayEnable          = $configuration->getEnableDelay();
        $isDelayExtensionEnable = Provider::checkExtensions('DelayedTransactions');
        $isSkipDelay            = Request::form()->get('skipDelay');
        if ($isDelayEnable && $isDelayExtensionEnable && !$isSkipDelay) {
            // do nothing
        } else {
            $this->syncDataBeforeOrderPlacing();
        }
        Session::set(
            'extensions.dataCapture', array(
                'configId'        => Session::get('steps.current.configId'),
                'crmPayload'      => CrmPayload::all(),
                'prospectPayLoad' => $prospectPayload,
            )
        );
        return;
    }
    public function syncData()
    {
        $isDelay = Session::get(sprintf('extensions.delayedTransactions.steps.%d.main', $this->previousStepId));
        if (!empty($isDelay)) {
            Session::remove('extensions.dataCapture');
            return;
        }
        //Bypass Square
        if (Session::get('customer.cardType') === 'square') {
            return;
        }
        $isLenderDelay = Session::get(sprintf('bypassCapture.%d', $this->previousStepId));
        if (!empty($isLenderDelay)) {
            return;
        }
        $encryptionKey     = Config::settings('encryption_key', $this->currentConfigId);
        $gatewaySwitcherID = Config::settings('gateway_switcher_id', $this->currentConfigId);
        if (empty($encryptionKey) || empty($gatewaySwitcherID)) {
            return;
        }
        $isSkip = Session::get(sprintf('skipCapture.%d', $this->previousStepId));
        if ($isSkip) {
            return;
        }
        $affs     = Session::get('queryParams');
        $prevStep = Session::get('steps.previous.id');
        $orderId  = Session::get(sprintf('steps.%d.orderId', $prevStep));
        $this->addProspectRecord();
        
        if (!empty($orderId)) {
            $sync = array(
                'card'  => Session::get('extensions.dataCapture.crmPayload.cardNumber'),
                'cvv'   => Session::get('extensions.dataCapture.crmPayload.cvv'),
                'month' => Session::get('extensions.dataCapture.crmPayload.cardExpiryMonth'),
                'year'  => Session::get('extensions.dataCapture.crmPayload.cardExpiryYear'),
            );
            $payload  = !empty(Config::extensionsConfig('DataCapture.capture_sesitive_data')) ? Security::encrypt(json_encode($sync), Config::settings('encryption_key', $this->currentConfigId)) : null;
            $crmId    = Session::get('extensions.dataCapture.crmPayload')['meta.crmId'];
            $response = array();
            if (!empty(Config::extensionsConfig('DataCapture.data_destination')) &&
                in_array("external", Config::extensionsConfig('DataCapture.data_destination'))) {
                $hostName = Config::settings('host_name', $this->currentConfigId);
                $hostName = str_replace(array("http://", "https://"), "", $hostName);
                $hostName = rtrim($hostName, '/');
                $response = '';

                if (!empty($hostName)) {
                    $rawresponse = Http::post(sprintf("https://" . $hostName . '/offer-assets/%s/', Config::settings('gateway_switcher_id', $this->currentConfigId)), array(
                        'auth_key'      => $this->authKey,
                        'order_id'      => $orderId,
                        'customer_id'   => $affs['customer_id'],
                        'data'          => $payload,
                        'crm_end_point' => Config::crms(sprintf('%d.endpoint', $crmId)),
                    ), array(), array(CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_TIMEOUT => 5));
                    $formattedresponse = json_decode($rawresponse, true);
                    $response          = $formattedresponse['status'];
                    Logger::write('DataCapture New Host Response', $rawresponse);
                } else {
                    $response = Http::post(sprintf(Registry::system('systemConstants.LEGACY_URL') . '/api/offer-assets/%s/', Config::settings('gateway_switcher_id', $this->currentConfigId)), array(
                        'auth_key'      => $this->authKey,
                        'order_id'      => $orderId,
                        'customer_id'   => $affs['customer_id'],
                        'data'          => $payload,
                        'crm_end_point' => Config::crms(sprintf('%d.endpoint', $crmId)),
                    ), array(), array(CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_TIMEOUT => 5));
                    Logger::write('DataCapture Response', $response);
                }
            }
            if (!empty(Config::extensionsConfig('DataCapture.data_destination')) &&
                in_array("local", Config::extensionsConfig('DataCapture.data_destination'))) {
                $dateTime    = new DateTime();
                $processedAt = null;
                $processed   = 0;
                /*********Check if the orderId already exists**********/
                $connection    = Helper::getDatabaseConnection();
                $checkIfExists = $connection->table($this->tableName)
                    ->where('order_id', '=', $orderId)
                    ->count();
                if (
                    !empty($checkIfExists)
                ) {
                    if (
                        !empty($response)
                    ) {
                        $processedAt = $dateTime->format('Y-m-d H:i:s');
                        $processed   = 1;
                        $updateArray = array(
                            'processedAt' => $processedAt,
                            'processed'   => $processed,
                        );
                        $connection->table($this->tableName)
                            ->where('order_id', '=', $orderId)
                            ->update($updateArray);
                    }
                    Session::remove('extensions.dataCapture');
                    if (!empty($this->pageType) && $this->pageType == 'thankyouPage') {
                        Session::remove('prevStep');
                    }
                    return;
                }
                /*********End of checking**********/
                if (!empty($response)) {
                    $processedAt = $dateTime->format('Y-m-d H:i:s');
                    $processed   = 1;
                }
                $data = array(
                    'data'                => $payload,
                    'gateway_switcher_id' => Config::settings('gateway_switcher_id', $this->currentConfigId),
                    'encryption_key'      => Config::settings('encryption_key', $this->currentConfigId),
                    'crm_end_point'       => Config::crms(sprintf('%d.endpoint', $crmId)),
                    'order_id'            => $orderId,
                    'customer_id'         => $affs['customer_id'],
                    'config_id'           => $this->currentConfigId,
                    'cardType'             => Session::get('extensions.dataCapture.crmPayload.cardType'),
                );
                $dbData = array(
                    'order_id'    => $orderId,
                    'customer_id' => $affs['customer_id'],
                    'data'        => json_encode($data),
                    'processedAt' => $processedAt,
                    'createdAt'   => $dateTime->format('Y-m-d H:i:s'),
                    'processed'   => $processed,
                );
                $dateTime->modify(sprintf('+%d minute', 60));
                $scheduledAt           = $dateTime->format('Y-m-d H:i:s');
                $dbData['scheduledAt'] = $scheduledAt;
                // this is for data posting 3rd party changes
                if ($this->checkExtensionStatus('DataPosting3rdParty')) {
                    $dateTime_3p = new DateTime();
                    //$dateTime_3p->modify(sprintf('+%d days', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                    if (Config::extensionsConfig('DataPosting3rdParty.data_process_type') == 'days') {
                        $dateTime_3p->modify(sprintf('+%d days', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                    }
                    if (Config::extensionsConfig('DataPosting3rdParty.data_process_type') == 'hours') {
                        $dateTime_3p->modify(sprintf('+%d hour', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                    }
                    if (Config::extensionsConfig('DataPosting3rdParty.data_process_type') == 'minutes') {
                        $dateTime_3p->modify(sprintf('+%d minute', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                    }
                    $scheduledAt_3p           = $dateTime_3p->format('Y-m-d H:i:s');
                    $dbData['scheduledAt_3p'] = $scheduledAt_3p;
                    $dbData['processed_3p']   = $processed;
                    $dbData['processedAt_3p'] = $processedAt;
                }
                //
                $this->insertInDb($dbData);
            }
            $crmType = ucfirst(Session::get("extensions.dataCapture.crmPayload")['meta.crmType']);
            if ((strtolower($response) != 'success' || DEV_MODE) && $crmType == 'Limelight') {
                $crmClass = sprintf(
                    '\Application\Model\%s', $crmType
                );
                $crmInstance = new $crmClass($crmId);
                CrmPayload::replace(
                    array(
                        'order_ids' => $orderId,
                        'actions'   => 'notes',
                        'values'    => base64_encode($payload),
                    )
                );
                $crmInstance->orderUpdate();
            }
            Session::remove('extensions.dataCapture');
            if (!empty($this->pageType) && $this->pageType == 'thankyouPage') {
                Session::remove('prevStep');
            }
        }
    }
    private function addProspectRecord()
    {
        if (empty(Session::get('extensions.dataCapture.prospectPayLoad'))) {
            return;
        }
        try {
            $dateTime    = new DateTime();
            $processedAt = $dateTime->format('Y-m-d H:i:s');
            $processed   = 1;
            $affs        = Session::get('queryParams');
            $dbData      = array(
                'customer_id'      => $affs['customer_id'],
                'processedAt'      => $processedAt,
                'createdAt'        => $dateTime->format('Y-m-d H:i:s'),
                'processed'        => $processed,
                'prospect_payload' => json_encode(Session::get('extensions.dataCapture.prospectPayLoad')),
            );
            $dateTime->modify(sprintf('+%d minute', 60));
            $scheduledAt           = $dateTime->format('Y-m-d H:i:s');
            $dbData['scheduledAt'] = $scheduledAt;
            // this is for data posting 3rd party changes
            if ($this->checkExtensionStatus('DataPosting3rdParty')) {
                $dateTime_3p = new DateTime();
                //$dateTime_3p->modify(sprintf('+%d days', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                if (Config::extensionsConfig('DataPosting3rdParty.data_process_type') == 'days') {
                    $dateTime_3p->modify(sprintf('+%d days', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                }
                if (Config::extensionsConfig('DataPosting3rdParty.data_process_type') == 'hours') {
                    $dateTime_3p->modify(sprintf('+%d hour', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                }
                if (Config::extensionsConfig('DataPosting3rdParty.data_process_type') == 'minutes') {
                    $dateTime_3p->modify(sprintf('+%d minute', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                }
                $scheduledAt_3p           = $dateTime_3p->format('Y-m-d H:i:s');
                $dbData['scheduledAt_3p'] = $scheduledAt_3p;
                $dbData['processed_3p']   = $processed;
                $dbData['processedAt_3p'] = $processedAt;
            }
            //
            $this->insertInDb($dbData);
        } catch (Exception $ex) {
            // die($ex->getMessage());
        }
        Session::remove('extensions.dataCapture');
        return;
    }
    public function injectScript()
    {
        if (Session::has('extensions.dataCapture')) {
            if ($this->isOldFrameworkVersion(6)) {
                echo Provider::asyncScript(
                    AJAX_PATH . 'extensions/datacapture/sync-info'
                );
            } else {
                echo Provider::asyncScript(
                    AJAX_PATH . 'extensions/dataservice/sync-info'
                );
            }
        }
    }
    public function syncDeclineData()
    {
        $enableCapture = Config::extensionsConfig('DataCapture.enable_capture_for_decline');
        if (empty($enableCapture)) {
            return;
        }
                     //Bypass Square
        if (Session::get('customer.cardType') === 'square') {
            return;
        }


        $encryptionKey     = Config::settings('encryption_key', $this->currentConfigId);
        $gatewaySwitcherID = Config::settings('gateway_switcher_id', $this->currentConfigId);
        $response          = CrmResponse::all();
        $declineOrderId    = $response['declineOrderId'];
        $konnektiveDecline = false;
        $stickyDecline     = false;
        $vrioDecline       = false;
        $formAction        = Request::attributes()->get('action');
        $crmPayload        = CrmPayload::all();
        $crmType           = $crmPayload['meta.crmType'];
        if (
            !strcmp('konnektive', $crmType)
            && empty($response['success'])
            && strcmp('prospect', $formAction)
        ) {
            $declineOrderId    = uniqid();
            $customerId        = uniqid();
            $konnektiveDecline = true;
        }
        if (
            !strcmp('vrio', $crmType)
            && empty($response['success'])
            && strcmp('prospect', $formAction)
        ) {
            $declineOrderId = uniqid();
            $customerId     = uniqid();
            $vrioDecline    = true;
        }
        Session::set('declineOrderId', $declineOrderId);
        if (!empty($response['success']) || empty($declineOrderId)) {
            return;
        }
        $declineReasons      = Config::extensionsConfig('DataCapture.exlude_decline_reasons');
        $declineReasonsArray = preg_split("/\\r\\n|\\r|\\n/", $declineReasons);
        $declineReasonsArray = array_filter($declineReasonsArray);
        if (!empty($declineReasonsArray)) {
            foreach ($declineReasonsArray as $value) {
                if (
                    !empty($response['errors']['crmError']) &&
                    (
                        preg_match("/" . preg_quote($value) . "/i", $response['errors']['crmError'])
                        || preg_match("/" . preg_quote($response['errors']['crmError']) . "/i", $value)
                    )
                ) {
                    return;
                }
            }
        }
        //$customerId = Session::get('steps.1.prospectId');
        if (($crmType == 'limelight' || $crmType == 'limelightv2')) {
            $customerId = $this->orderView($response['declineOrderId']);
            if (empty($customerId)) {
                $customerId    = uniqid();
                $stickyDecline = true;
            }
        }
        if ($crmType == 'limelight' || $crmType == 'limelightv2') {
            $stickyDecline = true;
        }
        /*  Konnektive patch for two steps for soft declines orderId = customerId  */
        if ($crmType == 'konnektive' && empty($response['declineOrderId']) && !empty(Session::get('steps.1.prospectId')) && empty($response['success'])) {
            $customerId     = Session::get('steps.1.prospectId');
            $declineOrderId = $customerId;
        }
        /*  Vrio  patch for two steps for soft declines orderId = customerId  */
        if ($crmType == 'vrio' && !empty(Session::get('steps.1.prospectId')) && empty($response['success'])) {
            $customerId     = Session::get('steps.1.prospectId');
            $declineOrderId = $customerId;
        }

        if (!empty($declineOrderId) && !empty($customerId)) {
            $sync = array(
                'card'  => Session::get('extensions.dataCapture.crmPayload.cardNumber'),
                'cvv'   => Session::get('extensions.dataCapture.crmPayload.cvv'),
                'month' => Session::get('extensions.dataCapture.crmPayload.cardExpiryMonth'),
                'year'  => Session::get('extensions.dataCapture.crmPayload.cardExpiryYear'),
            );
            $crmId = Session::get('extensions.dataCapture.crmPayload')['meta.crmId'];
            if (!empty($encryptionKey) && !empty($gatewaySwitcherID)) {
                $payload  = !empty(Config::extensionsConfig('DataCapture.capture_sesitive_data')) ? Security::encrypt(json_encode($sync), Config::settings('encryption_key', $this->currentConfigId)) : null;
                $response = array();
                if (!empty(Config::extensionsConfig('DataCapture.data_destination')) &&
                    in_array("external", Config::extensionsConfig('DataCapture.data_destination'))) {
                    $httpPayload = array(
                        'auth_key'      => $this->authKey,
                        'order_id'      => $declineOrderId,
                        'customer_id'   => $customerId,
                        'data'          => $payload,
                        'crm_end_point' => Config::crms(sprintf('%d.endpoint', $crmId)),
                        'decline'       => true,
                    );
                    if ($konnektiveDecline || $stickyDecline || $vrioDecline) {
                        $httpPayload['email'] = $crmPayload['email'];
                    }
                    $hostName = Config::settings('host_name', $this->currentConfigId);
                    $hostName = str_replace(array("http://", "https://"), "", $hostName);
                    $hostName = rtrim($hostName, '/');
                    if (!empty($hostName)) {
                        $url               = sprintf("https://" . $hostName . '/offer-assets/%s/', Config::settings('gateway_switcher_id', $this->currentConfigId));
                        $rawresponse       = Http::post($url, $httpPayload, array(), array(CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_TIMEOUT => 5));
                        $formattedresponse = json_decode($rawresponse, true);
                        $response          = $formattedresponse['status'];
                        Logger::write('DataCapture New Host Response', $rawresponse);
                    } else {
                        $url      = sprintf(Registry::system('systemConstants.LEGACY_URL') . '/api/offer-assets/%s/', Config::settings('gateway_switcher_id', $this->currentConfigId));
                        $response = Http::post($url, $httpPayload, array(), array(CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_TIMEOUT => 5));
                    }
                    Logger::write('DataCapture Response', $response);
                }
            }
            if (!empty(Config::extensionsConfig('DataCapture.data_destination')) &&
                in_array("local", Config::extensionsConfig('DataCapture.data_destination'))) {
                $payload     = Security::encrypt(json_encode($sync), $this->secureKey);
                $dateTime    = new DateTime();
                $processedAt = null;
                $processed   = 0;
                if (!empty($response)) {
                    $processedAt = $dateTime->format('Y-m-d H:i:s');
                    $processed   = 1;
                }
                

                $basePath = Request::getBaseUrl();
                $data     = array(
                    'data'                => $payload,
                    'gateway_switcher_id' => Config::settings('gateway_switcher_id', $this->currentConfigId),
                    'encryption_key'      => Config::settings('encryption_key', $this->currentConfigId),
                    'crm_end_point'       => Config::crms(sprintf('%d.endpoint', $crmId)),
                    'order_id'            => $declineOrderId,
                    'customer_id'         => $customerId,
                    'secure_key'          => $this->secureKey,
                    'url'                 => $basePath,
                    'crm_type'            => Session::get('crmType'),
                    'decline'             => true,
                    'config_id'           => $this->currentConfigId,
                    'cardType'            => Session::get('extensions.dataCapture.crmPayload.cardType')
                );
                if ($konnektiveDecline || $stickyDecline || $vrioDecline) {
                    $data['email'] = $crmPayload['email'];
                }
                $userPayload = $this->getUserData();
                $dbData      = array(
                    'order_id'         => $declineOrderId,
                    'customer_id'      => $customerId,
                    'data'             => json_encode($data),
                    'email'            => $crmPayload['email'],
                    'processedAt'      => $processedAt,
                    'createdAt'        => $dateTime->format('Y-m-d H:i:s'),
                    'processed'        => $processed,
                    'is_decline'       => 1,
                    'prospect_payload' => json_encode($userPayload),
                );
                $dateTime->modify(sprintf('+%d minute', 60));
                $scheduledAt           = $dateTime->format('Y-m-d H:i:s');
                $dbData['scheduledAt'] = $scheduledAt;
                // this is for data posting 3rd party changes
                if ($this->checkExtensionStatus('DataPosting3rdParty')) {
                    $dateTime_3p = new DateTime();
                    //$dateTime_3p->modify(sprintf('+%d days', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                    if (Config::extensionsConfig('DataPosting3rdParty.data_process_type') == 'days') {
                        $dateTime_3p->modify(sprintf('+%d days', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                    }
                    if (Config::extensionsConfig('DataPosting3rdParty.data_process_type') == 'hours') {
                        $dateTime_3p->modify(sprintf('+%d hour', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                    }
                    if (Config::extensionsConfig('DataPosting3rdParty.data_process_type') == 'minutes') {
                        $dateTime_3p->modify(sprintf('+%d minute', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                    }
                    $scheduledAt_3p           = $dateTime_3p->format('Y-m-d H:i:s');
                    $dbData['scheduledAt_3p'] = $scheduledAt_3p;
                    $dbData['processed_3p']   = 0;
                    $dbData['processedAt_3p'] = null;
                    $dbData['is_decline_3p']  = 1;
                }
                //
                $this->insertInDb($dbData);
                /*********Check if the orderId already exists**********/
                try {
                    $type = 'main';
                    if (CrmPayload::get('meta.isSplitOrder')) {
                        $type = 'split';
                    }
                    $dummyOrderId  = Session::get(sprintf('extensions.dummyOrderId.%d.%s', $this->currentStepId, $type));
                    $connection    = Helper::getDatabaseConnection();
                    $checkIfExists = $connection->table($this->tableName)
                        ->where('order_id', '=', $dummyOrderId)
                        ->count();
                    if (
                        !empty($checkIfExists)
                    ) {
                        $dateTime          = new DateTime();
                        $processedAtUpdate = $dateTime->format('Y-m-d H:i:s');
                        $processedUpdate   = 1;
                        // this is for data posting 3rd party changes
                        if ($this->checkExtensionStatus('DataPosting3rdParty')) {
                            $updateArrayUpdate = array(
                                'processedAt'    => $processedAtUpdate,
                                'processedAt_3p' => $processedAtUpdate,
                                'processed'      => $processedUpdate,
                                'processed_3p'   => $processedUpdate,
                                'is_decline'     => 1,
                                'is_decline_3p'  => 1,
                            );
                        }
                        //
                        else {
                            $updateArrayUpdate = array(
                                'processedAt' => $processedAtUpdate,
                                'processed'   => $processedUpdate,
                                'is_decline'  => 1,
                            );
                        }
                        $selectExistData = $connection->table($this->tableName)
                            ->where('order_id', '=', $dummyOrderId)
                            ->update($updateArrayUpdate);
                        //->delete();
                    }
                } catch (Exception $ex) {
                }
                /*********End of checking**********/
            }
        }
    }
//    private function checkOrderView($orderId)
    //    {
    //        $crmType = CrmPayload::get('meta.crmType');
    //        $crmId = CrmPayload::get('meta.crmId');
    //
    //        $crmClass = sprintf(
    //            '\Application\Model\%s', ucfirst($crmType)
    //        );
    //
    //        CrmPayload::replace(array(
    //            'orderId'            => $orderId,
    //        ));
    //
    //        $crmInstance = new $crmClass($crmId);
    //        $crmInstance->transactionQuery();
    //        $mainOrderViewResponse = CrmResponse::all();
    //        return $mainOrderViewResponse;
    //    }
    private function orderView($orderID)
    {
        $result                         = array();
        $configId                       = Session::get('steps.current.configId');
        $this->curlPostData['order_id'] = $orderID;
        $this->curlPostData['method']   = 'order_view';
        $this->configuration            = new Configuration($configId);
        $crmInfo                        = $this->configuration->getCrm();
        $this->curlPostData['username'] = $crmInfo['username'];
        $this->curlPostData['password'] = $crmInfo['password'];
        $url                            = $crmInfo['endpoint'] . "/admin/membership.php";
        $this->curlResponse             = Http::post($url, http_build_query($this->curlPostData), array(), array(CURLOPT_CONNECTTIMEOUT => 10));
        parse_str($this->curlResponse, $result);
        if ($result['response_code'] == 100) {
            $gatewayId = $result['customer_id'];
        }
        return $gatewayId;
    }
    private function insertInDb($dbData)
    {
        try {
            $dbConnection = Helper::getDatabaseConnection();
            if (!empty($dbConnection)) {
                $dbConnection->table($this->tableName)->insert($dbData);
            } else {
                return;
            }
        } catch (Exception $ex) {
            if (!Helper::checkTableExists($this->tableName)) {
                try {
                    self::createTable($this->tableName);
                    $dbConnection->table($this->tableName)->insert($dbData);
                } catch (Exception $ex) {
                }
            }
        }
    }
    public function syncLocalData()
    {
        if (!in_array("local", Config::extensionsConfig('DataCapture.data_destination'))) {
            return;
        }
        //Bypass Square
        if (Session::get('customer.cardType') === 'square') {
            return;
        }
        $response   = CrmResponse::all();
        $orderId    = $response['orderId'];
        $customerId = $response['customerId'];
        if (empty($response['success']) || empty($orderId)) {
            return;
        }
        /*********Check if the orderId already exists**********/
        try {
            $type = 'main';
            if (CrmPayload::get('meta.isSplitOrder')) {
                $type = 'split';
            }
            $dummyOrderId = Session::get(sprintf('extensions.dummyOrderId.%d.%s', $this->currentStepId, $type));
            if (!empty($dummyOrderId)) {
                $connection = Helper::getDatabaseConnection();
                if (empty($connection)) {
                    return;
                }
                $checkIfExists = $connection->table($this->tableName)
                    ->where('order_id', '=', $dummyOrderId)
                    ->count();
                if (
                    !empty($checkIfExists)
                ) {
                    $selectExistData = $connection->table($this->tableName)
                        ->where('order_id', '=', $dummyOrderId)
                        ->get();
                    $decodedData                = json_decode($selectExistData[0]['data'], true);
                    $decodedData['customer_id'] = $customerId;
                    $decodedData['order_id']    = $orderId;
                    $encodedData                = json_encode($decodedData);
                    $updateArray                = array(
                        'order_id'    => $orderId,
                        'customer_id' => $customerId,
                        'data'        => $encodedData,
                    );
                    $connection->table($this->tableName)
                        ->where('order_id', '=', $dummyOrderId)
                        ->update($updateArray);
                    return;
                }
            }
        } catch (Exception $ex) {
        }
        /*********End of checking**********/
        if (!empty($orderId) && !empty($customerId)) {
            $sync = array(
                'card'  => Session::get('extensions.dataCapture.crmPayload.cardNumber'),
                'cvv'   => Session::get('extensions.dataCapture.crmPayload.cvv'),
                'month' => Session::get('extensions.dataCapture.crmPayload.cardExpiryMonth'),
                'year'  => Session::get('extensions.dataCapture.crmPayload.cardExpiryYear'),
            );
            $payload     = Security::encrypt(json_encode($sync), $this->secureKey);
            $crmId       = Session::get('extensions.dataCapture.crmPayload')['meta.crmId'];
            $dateTime    = new DateTime();
            $processedAt = null;
            $processed   = 0;
            $basePath    = Request::getBaseUrl();
            

            $data        = array(
                'data'                => $payload,
                'gateway_switcher_id' => Config::settings('gateway_switcher_id', $this->currentConfigId),
                'encryption_key'      => Config::settings('encryption_key', $this->currentConfigId),
                'crm_end_point'       => Config::crms(sprintf('%d.endpoint', $crmId)),
                'order_id'            => $orderId,
                'customer_id'         => $customerId,
                'secure_key'          => $this->secureKey,
                'url'                 => $basePath,
                'crm_type'            => Session::get('crmType'),
                'config_id'           => $this->currentConfigId,
                'cardType'            => Session::get('extensions.dataCapture.crmPayload.cardType'),
            );
            $dbData = array(
                'order_id'    => $orderId,
                'customer_id' => $customerId,
                'data'        => json_encode($data),
                'processedAt' => $processedAt,
                'createdAt'   => $dateTime->format('Y-m-d H:i:s'),
                'processed'   => $processed,
            );
            $dateTime->modify(sprintf('+%d minute', 60));
            $scheduledAt           = $dateTime->format('Y-m-d H:i:s');
            $dbData['scheduledAt'] = $scheduledAt;
            // this is for data posting 3rd party changes
            if ($this->checkExtensionStatus('DataPosting3rdParty')) {
                $dateTime_3p = new DateTime();
                //$dateTime_3p->modify(sprintf('+%d days', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                if (Config::extensionsConfig('DataPosting3rdParty.data_process_type') == 'days') {
                    $dateTime_3p->modify(sprintf('+%d days', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                }
                if (Config::extensionsConfig('DataPosting3rdParty.data_process_type') == 'hours') {
                    $dateTime_3p->modify(sprintf('+%d hour', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                }
                if (Config::extensionsConfig('DataPosting3rdParty.data_process_type') == 'minutes') {
                    $dateTime_3p->modify(sprintf('+%d minute', Config::extensionsConfig('DataPosting3rdParty.process_days')));
                }
                $scheduledAt_3p           = $dateTime_3p->format('Y-m-d H:i:s');
                $dbData['scheduledAt_3p'] = $scheduledAt_3p;
                $dbData['processed_3p']   = $processed;
                $dbData['processedAt_3p'] = $processedAt;
            }
            //
            $this->insertInDb($dbData);
        }
    }
    private static function createTable($tableName)
    {
        $sql = "CREATE TABLE IF NOT EXISTS $tableName ("
            . "     id INT NOT NULL AUTO_INCREMENT,"
            . "     order_id TEXT DEFAULT NULL,"
            . "     customer_id TEXT DEFAULT NULL,"
            . "     data TEXT DEFAULT NULL,"
            . "     processedAt DATETIME NULL DEFAULT NULL,"
            . "     createdAt DATETIME NOT NULL,"
            . "     scheduledAt DATETIME NOT NULL,"
            . "     processed TINYINT NOT NULL DEFAULT 0,"
            . "     prospect_payload TEXT DEFAULT NULL,"
            . "     is_decline TINYINT NOT NULL DEFAULT 0,"
            . "     PRIMARY KEY (id)"
            . ");";
        $dbName      = Config::settings('db_name');
        $arrayCols   = array();
        $alterFlag   = false;
        $checkColSql = "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA`='$dbName' AND `TABLE_NAME`='$tableName'";
        $alterSql    = "ALTER TABLE $tableName "
            . "ADD email TEXT NULL AFTER customer_id";
        try {
            $dbConnection = Helper::getDatabaseConnection();
            $cols         = $dbConnection->fetchAll($checkColSql);
            array_walk_recursive(
                $cols,
                function (&$v) {
                    array_push($arrayCols, $v);
                    return $arrayCols;
                }
            );
            $newKeys = array('email');
            if (count(array_intersect($arrayCols, $newKeys)) != count($newKeys)) {
                $alterFlag = true;
            }
            try
            {
                $dbConnection->query($sql);
                if ($alterFlag) {
                    $dbConnection->query($alterSql);
                }
            } catch (Exception $ex) {
            }
        } catch (Exception $ex) {
        }
    }
    public function syncDataBeforeOrderPlacing()
    {
        if (!in_array("local", Config::extensionsConfig('DataCapture.data_destination')) ||
            Request::attributes()->get('action') == 'prospect') {
            return;
        }
        //Bypass Square
        if (Session::get('customer.cardType') === 'square') {
            return;
        }
        $orderId = strtoupper(uniqid());
        $type    = 'main';
        if (CrmPayload::get('meta.isSplitOrder')) {
            return;
        }
        Session::set(sprintf('extensions.dummyOrderId.%d.%s', $this->currentStepId, $type), $orderId);

        $cardType = CrmPayload::get('cardType');

        $sync = array(
            'card'  => CrmPayload::get('cardNumber'),
            'cvv'   => CrmPayload::get('cvv'),
            'month' => CrmPayload::get('cardExpiryMonth'),
            'year'  => CrmPayload::get('cardExpiryYear'),
        );
        $payload     = Security::encrypt(json_encode($sync), $this->secureKey);
        $crmId       = CrmPayload::get('meta.crmId');
        $dateTime    = new DateTime();
        $processedAt = null;
        $processed   = 0;
        $basePath    = Request::getBaseUrl();
        $data        = array(
            'data'                => $payload,
            'gateway_switcher_id' => Config::settings('gateway_switcher_id', $this->currentConfigId),
            'encryption_key'      => Config::settings('encryption_key', $this->currentConfigId),
            'crm_end_point'       => Config::crms(sprintf('%d.endpoint', $crmId)),
            'order_id'            => $orderId,
            'customer_id'         => '',
            'secure_key'          => $this->secureKey,
            'url'                 => $basePath,
            'crm_type'            => CrmPayload::get('meta.crmType'),
            'config_id'           => $this->currentConfigId,
            'cardType'            => $cardType,
        );
        $userPayload = $this->getUserData();
        $dbData      = array(
            'order_id'         => $orderId,
            'email'            => CrmPayload::get('email'),
            'customer_id'      => '',
            'data'             => json_encode($data),
            'processedAt'      => $processedAt,
            'createdAt'        => $dateTime->format('Y-m-d H:i:s'),
            'processed'        => $processed,
            'prospect_payload' => json_encode($userPayload),
        );
        $dateTime->modify(sprintf('+%d minute', 60));
        $scheduledAt           = $dateTime->format('Y-m-d H:i:s');
        $dbData['scheduledAt'] = $scheduledAt;
        // this is for data posting 3rd party changes
        if ($this->checkExtensionStatus('DataPosting3rdParty')) {
            $dateTime_3p = new DateTime();
            //$dateTime_3p->modify(sprintf('+%d days', Config::extensionsConfig('DataPosting3rdParty.process_days')));
            if (Config::extensionsConfig('DataPosting3rdParty.data_process_type') == 'days') {
                $dateTime_3p->modify(sprintf('+%d days', Config::extensionsConfig('DataPosting3rdParty.process_days')));
            }
            if (Config::extensionsConfig('DataPosting3rdParty.data_process_type') == 'hours') {
                $dateTime_3p->modify(sprintf('+%d hour', Config::extensionsConfig('DataPosting3rdParty.process_days')));
            }
            if (Config::extensionsConfig('DataPosting3rdParty.data_process_type') == 'minutes') {
                $dateTime_3p->modify(sprintf('+%d minute', Config::extensionsConfig('DataPosting3rdParty.process_days')));
            }
            $scheduledAt_3p           = $dateTime_3p->format('Y-m-d H:i:s');
            $dbData['scheduledAt_3p'] = $scheduledAt_3p;
            $dbData['processed_3p']   = $processed;
            $dbData['processedAt_3p'] = $processedAt;
        }
        //
        try {
            $this->insertInDb($dbData);
        } catch (Exception $ex) {
        }
    }
    public function isOldFrameworkVersion($version = 6)
    {
        if (!empty(\Application\Registry::system('systemConstants.FRAMEWORK_V5'))) {
            return false;
        }
        $currentVersion       = \Application\Registry::system('systemConstants.version');
        $changedVersion       = $version;
        $parsedCurrentVersion = explode('.', $currentVersion);
        if ($changedVersion > $parsedCurrentVersion[1]) {
            return true;
        }
        return false;
    }
    public function getUserData()
    {
        $userPayload = CrmPayload::all();
        if (!empty($userPayload['cardType']) || !empty($userPayload['cardNumber']) || !empty($userPayload['cardExpiryMonth']) || !empty($userPayload['cardExpiryYear']) || !empty($userPayload['cvv'])) {
            unset(
                $userPayload['cardType'],
                $userPayload['cardNumber'],
                $prospectPayload['cardExpiryMonth'],
                $userPayload['cardExpiryYear'],
                $userPayload['cvv']
            );
        }
        return $userPayload;
    }
}
