<?php

namespace KupShop\I18nBundle\Util;

use KupShop\KupShopBundle\Util\Compat\SymfonyBridge;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\RequestStack;

class IPGeoLocator
{
    // caching server for geoPlugin server
    protected $host;

    // the default base currency
    protected $currency = 'CZK';

    protected $cache;
    protected $proxyCache;

    /**
     * @var RequestStack
     */
    protected $requestStack;

    protected $logger;

    public function __construct(RequestStack $requestStack, LoggerInterface $logger)
    {
        $this->requestStack = $requestStack;
        $this->logger = $logger;

        $urlSuffix = '/geoip?ip={IP}&base_currency={CURRENCY}&id_shop={ID_SHOP}';
        $this->host = (isRunningOnCluster() ? 'geoip.services' : 'http://geoip.wpj.cz').$urlSuffix;
    }

    /**
     * Gets geographical info from users request. When proxy is enabled, it tries to take the info from the headers that the proxy set.
     *
     * @param $fullInfo bool when false, guaranteed IPGeoLocatorResult attributes are only ip, countryCode and currencyCode. When more information is needed (e.g. latitude/longitude), fullInfo parameter has to be true
     *
     * @return IPGeoLocatorResult
     */
    public function getInfo(bool $fullInfo = false)
    {
        $result = null;

        if (findModule(\Modules::PROXY_CACHE) && !$fullInfo) {
            $result = $this->getInfoFromProxy();
        }

        if (!$result) {
            $result = $this->getGeoLocatorInfo();
        }

        return $result;
    }

    protected function getGeoLocatorInfo()
    {
        if ($this->cache) {
            return $this->cache;
        }

        $ip = $this->getClientIp();

        $data = $this->locate($ip);

        return $this->cache = $this->createResult($data);
    }

    protected function getInfoFromProxy()
    {
        if ($this->proxyCache) {
            return $this->proxyCache;
        }

        $countryCode = $this->getRequest()->headers->get('Cdn-Requestcountrycode');

        if (!$countryCode) {
            return false;
        }

        $currencyCode = (new \NumberFormatter('en_'.$countryCode, \NumberFormatter::CURRENCY))->getTextAttribute(\NumberFormatter::CURRENCY_CODE);

        if (!$currencyCode || $currencyCode == 'XXX') {
            return false;
        }

        $data = [
            'geoplugin_countryCode' => $countryCode,
            'geoplugin_currencyCode' => $currencyCode,
            'ip' => $this->getClientIp(),
        ];

        return $this->proxyCache = $this->createResult($data);
    }

    protected function getClientIp()
    {
        return $this->getRequest()->getClientIp();
    }

    protected function getRequest()
    {
        $request = $this->requestStack->getMainRequest();

        if (is_null($request)) {
            $request = SymfonyBridge::getCurrentRequest();
        }

        return $request;
    }

    protected function fetch($host)
    {
        // use cURL to fetch data
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $host);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_USERAGENT, 'geoPlugin PHP Class v1.0');
        curl_setopt($ch, CURLOPT_TIMEOUT_MS, 1000);
        $response = curl_exec($ch);
        curl_close($ch);

        return $response;
    }

    protected function locate($ip)
    {
        $host = str_replace('{IP}', $ip, $this->host);
        $host = str_replace('{CURRENCY}', $this->currency, $host);
        $host = str_replace('{ID_SHOP}', getShopUniqueName(), $host);

        $response = $this->fetch($host);

        return json_decode($response, true);
    }

    /**
     * @param $data array
     *
     * @return IPGeoLocatorResult
     */
    protected function createResult($data)
    {
        $result = new IPGeoLocatorResult();

        // set the geoPlugin vars
        $result->ip = $data['ip'] ?? null;
        $result->city = $data['geoplugin_city'] ?? null;
        $result->region = $data['geoplugin_region'] ?? null;
        $result->areaCode = $data['geoplugin_areaCode'] ?? null;
        $result->dmaCode = $data['geoplugin_dmaCode'] ?? null;
        $result->countryCode = $data['geoplugin_countryCode'] ?? null;
        $result->countryName = $data['geoplugin_countryName'] ?? null;
        $result->continentCode = $data['geoplugin_continentCode'] ?? null;
        $result->latitude = $data['geoplugin_latitude'] ?? null;
        $result->longitude = $data['geoplugin_longitude'] ?? null;
        $result->currencyCode = $data['geoplugin_currencyCode'] ?? null;
        $result->currencySymbol = $data['geoplugin_currencySymbol'] ?? null;
        $result->currencyConverter = $data['geoplugin_currencyConverter'] ?? null;

        return $result;
    }
}
