<?php

declare(strict_types=1);

namespace Paysera\CheckoutSdk\Service\Normalizer;

use Paysera\CheckoutSdk\Entity\Collection\PaymentCountryCollection;
use Paysera\CheckoutSdk\Entity\PaymentCountry;
use Paysera\CheckoutSdk\Entity\PaymentMethod;
use Paysera\CheckoutSdk\Service\Provider\PaymentMethodIconResolver;
use Paysera\CheckoutSdk\Util\TypeConverter;

class PaymentMethodNormalizer
{
    private const ALLOWED_ICON_URL_SCHEMES = ['http', 'https'];

    private TypeConverter $typeConverter;
    private PaymentMethodIconResolver $iconResolver;

    public function __construct(TypeConverter $typeConverter, PaymentMethodIconResolver $iconResolver)
    {
        $this->typeConverter = $typeConverter;
        $this->iconResolver = $iconResolver;
    }

    public function denormalize(array $rawData): PaymentMethod
    {
        $key = $this->getProviderProperty('key', $rawData);

        return new PaymentMethod(
            $key,
            $this->getProviderProperty('title', $rawData),
            $this->getProviderProperty('description', $rawData),
            $this->getProviderProperty('type', $rawData),
            $this->getProviderProperty('flow', $rawData),
            $this->normalizeCountries($rawData['available_countries'] ?? []),
            $this->resolveIconUrl($key, $rawData)
        );
    }

    protected function getProviderProperty(
        string $propertyName,
        array $rawData
    ): string {
        if (isset($rawData[$propertyName]) === false) {
            return '';
        }

        return $this->typeConverter->convert($rawData[$propertyName], TypeConverter::STRING);
    }

    private function normalizeCountries(array $countries): PaymentCountryCollection
    {
        $collection = new PaymentCountryCollection();

        foreach ($countries as $country) {
            $collection->append(
                new PaymentCountry($this->typeConverter->convert($country, TypeConverter::STRING))
            );
        }

        return $collection;
    }

    private function resolveIconUrl(string $key, array $rawData): string
    {
        $apiIconUrl = $this->getProviderProperty('icon_url', $rawData);

        if ($apiIconUrl !== '' && $this->isSafeHttpUrl($apiIconUrl)) {
            return $apiIconUrl;
        }

        return $this->iconResolver->resolve($key);
    }

    private function isSafeHttpUrl(string $url): bool
    {
        if (preg_match('/[\x00-\x1F\x7F]/', $url) === 1) {
            return false;
        }

        if (filter_var($url, FILTER_VALIDATE_URL) === false) {
            return false;
        }

        $scheme = parse_url($url, PHP_URL_SCHEME);

        return is_string($scheme) && in_array(strtolower($scheme), self::ALLOWED_ICON_URL_SCHEMES, true);
    }
}
