<?php

namespace Extension\VisitorBlocker;

use Application\Request;
use Database\Connectors\ConnectionFactory;
use Application\Session;
use Application\Http;
use Application\Response;
use Application\Config;
use Application\CrmPayload;
use Exception;
use Application\Registry;

class BlacklistService
{

    protected $cardBin, $apiKey, $binResponse, $cc;
    protected $isFraudBin = false;
    protected $binDeclineText = 'Invalid credit card, Please try a different card.';
    protected $zipDeclineText = 'Invalid zip, Please try a different zip.';
    protected $emailDeclineText = 'Invalid email, Please try a different email.';
    protected $ipDeclineText = 'Invalid IP address, Please try with diffrent IP address';
    protected $declineText;

    public function __construct()
    {
        $this->pageType = Session::get('steps.current.pageType');
        $this->currentStep = (int) Session::get('steps.current.id');
        $this->authKey = Registry::system('systemConstants.LEGACY_AUTH_KEY');
        $this->remoteURL = Registry::system('systemConstants.LEGACY_URL');
        $this->gatewaySwitcherId = Config::settings('gateway_switcher_id');
        $this->config = Config::extensionsConfig('VisitorBlocker');
        $this->storagePath = STORAGE_DIR . DS;
    }

    public function captureCrmPayload()
    {
        if(!strncmp($this->config['block_engine'], 'remote', strlen('remote')) && $this->config['enable_blacklist_service']) {
            if ($this->blockOrder())
            {
                Response::send(array(
                    'success' => false,
                    'errors' => array(
                        'binerror' => $this->declineText
                    )
                ));
            }
        }
    }

    protected function blockOrder()
    {
        if (!$this->gatewaySwitcherId)
        {
            return false;
        }

        $blacklist = $this->getBlackList();

        if ($blacklist)
        {

            if (!empty($blacklist['zip-code']) && in_array(Session::get('customer.shippingZip'), $blacklist["zip-code"]))
            {
                $this->declineText = !empty($this->config['zip_block_message']) ? $this->config['zip_block_message'] : $this->zipDeclineText;
                return true;
            }

            if (!empty($blacklist['ip-address']) && in_array(Request::getClientIp(), $blacklist['ip-address']))
            {
               $this->declineText = !empty($this->config['ip_block_message']) ? $this->config['ip_block_message'] : $this->ipDeclineText;
               return true;
            }

            if (!empty($blacklist['email']))
            {
                foreach ($blacklist['email'] as $email)
                {

                    if (preg_match("/^" . $email . "$/", Session::get('customer.email')))
                    {
                        $this->declineText = !empty($this->config['email_block_message']) ? $this->config['email_block_message'] : $this->emailDeclineText;
                        return true;
                    }

                    $email_domain = explode('@', Session::get('customer.email'));
                    if (preg_match("/^" . $email . "$/", $email_domain[1]))
                    {
                        $this->declineText = !empty($this->config['email_block_message']) ? $this->config['email_block_message'] : $this->emailDeclineText;
                        return true;
                    }

                    $emailDomainExt = explode('.', Session::get('customer.email'));
                    $emailDomainExt = end($emailDomainExt);
                    if ($emailDomainExt === $email)
                    {
                        $this->declineText = !empty($this->config['email_block_message']) ? $this->config['email_block_message'] : $this->emailDeclineText;
                        return true;
                    }
                }
            }

            $cardNumber = CrmPayload::has('cardNumber') ? CrmPayload::get('cardNumber') : Session::get('customer.cardNumber');

            if (empty($cardNumber))
            {
                return;
            }

            $this->cc = $cardNumber;
            $this->cardBin = substr($this->cc, 0, 6);

            foreach ($blacklist['card-no'] as $card)
            {

                if (strpos($card, substr($this->cc, 0, 4)) !== false && strpos($card, substr($this->cc, 4, -4)) !== false)
                {
                    $this->declineText = !empty($this->config['card_number_block_message']) ? $this->config['card_number_block_message'] : $this->binDeclineText;
                    return true;
                }
            }
        }

        if (!empty($this->cardBin))
        {

            if ($this->checkPrepaidBin())
            {
                //Invalid credit card, Please try a different card.
                $this->declineText = !empty($this->config['bin_block_message']) ? $this->config['bin_block_message'] : $this->binDeclineText;
                return true;
            }
        }


        return false;
    }

    protected function checkPrepaidBin()
    {

        $cacheFile = $this->storagePath . 'bins.json';
        $data = file_get_contents($cacheFile);

        if (filemtime($cacheFile) + ($this->config['cache_refreash_rate'] * 60 * 60) < time() || strlen($data) < 1)
        {

            $data = Http::get($this->remoteURL . '/api/black-list/' . $this->gatewaySwitcherId . '/');
            file_put_contents(($cacheFile), $data);
        }

        $o = json_decode($data);

        if (!$o)
        {
            return false;
        }

        $bins = array();

        foreach ($o as $key => $value)
        {
            $bins = array_merge($bins, explode("\r\n", $value->action_values));
        }

        foreach ($bins as $bin)
        {
            if ($this->cardBin == $bin)
            {
                return true;
            }
        }
    }

    public function pullData()
    {
        try
        {
            $binCacheFile = $this->storagePath . 'bins.json';
            $blacklistCacheFile = $this->storagePath . 'blacklist.json';
            $data = Http::get($this->remoteURL . '/api/black-list/' . $this->gatewaySwitcherId . '/');
            file_put_contents(($binCacheFile), $data);
            file_put_contents(($blacklistCacheFile), $data);
        }
        catch (Exception $e)
        {
        }
    }

    protected function getBlackList()
    {

        if (!$clientID = $this->gatewaySwitcherId)
        {
            return false;
        }

        $cacheFile = $this->storagePath . 'blacklist.json';

        $modified = filemtime($cacheFile);

        if (time() - $modified > (60 * 60))
        {

            $data = Http::get($this->remoteURL . '/api/black-list/' . $clientID . '/');

            file_put_contents($cacheFile, $data);
        }
        else
        {
            $data = file_get_contents($cacheFile);
        }

        $blacklist = json_decode($data, true);

        if (empty($blacklist))
        {
            return array();
        }

        $bl = array();

        foreach ($blacklist as $key => $value)
        {
            $bl[$value['type']] = preg_split('/\n|\r\n?/', $value['action_values']);
        }

        return $bl;
    }

}
