<?php

declare(strict_types=1);

namespace Gls\GlsPoland\DataProvider;

use Gls\GlsPoland\AdePlus\Common\Services;
use Gls\GlsPoland\AdePlus\Services\ClientInterface;
use Gls\GlsPoland\AdePlus\Services\MaxParcelWeights;
use Psr\Cache\CacheItemPoolInterface;

final class ServiceInformationProvider
{
    //
    public const MAX_COD_AMOUNT_PLN = 6000.;
    public const MAX_DOMESTIC_PARCEL_WEIGHT_KG = 31.5;
    public const MAX_INTL_PARCEL_WEIGHT_KG = 40.;
    public const SDS_AVAILABLE_COUNTRIES = ['PL', 'DE', 'AT', 'BE', 'DK', 'FI', 'FR', 'HU', 'IE', 'LU', 'NL', 'PT', 'SK', 'ES'];

    private $cache;
    private $client;

    public function __construct(CacheItemPoolInterface $cache, ClientInterface $client)
    {
        $this->cache = $cache;
        $this->client = $client;
    }

    public function getShopDeliveryAvailableCountries(): array
    {
        return $this->getCached('gls_poland_sds_countries', [$this->client, 'getShopDeliveryAvailableCountries'], self::SDS_AVAILABLE_COUNTRIES);
    }

    public function getMaxCashOnDeliveryAmount(): float
    {
        return $this->getCached('gls_poland_max_cod_amount', [$this->client, 'getMaxCashOnDeliveryAmount'], self::MAX_COD_AMOUNT_PLN);
    }

    public function getGuaranteedServices(string $zipCode): ?Services
    {
        return $this->getCached('gls_poland_guaranteed_services_' . $zipCode, function () use ($zipCode) {
            return $this->client->getGuaranteedServices($zipCode);
        });
    }

    public function getMaxDomesticParcelWeight(): float
    {
        if (null === $maxWeights = $this->getMaxParcelWeights()) {
            return self::MAX_DOMESTIC_PARCEL_WEIGHT_KG;
        }

        return $maxWeights->getMaxDomesticWeightKg();
    }

    public function getMaxInternationalParcelWeight(): float
    {
        if (null === $maxWeights = $this->getMaxParcelWeights()) {
            return self::MAX_INTL_PARCEL_WEIGHT_KG;
        }

        return $maxWeights->getMaxInternationalWeightKg();
    }

    private function getMaxParcelWeights(): ?MaxParcelWeights
    {
        return $this->getCached('gls_poland_max_parcel_weights', [$this->client, 'getMaxParcelWeights']);
    }

    private function getCached(string $key, callable $getter, $default = null)
    {
        $item = $this->cache->getItem($key);

        if ($item->isHit()) {
            return $item->get();
        }

        try {
            $value = $getter();

            $item->set($value);
            $item->expiresAfter(new \DateInterval('P1D'));

            $this->cache->save($item);

            return $value;
        } catch (\Exception $e) {
            return $value ?? $default;
        }
    }
}
