<?php

namespace Autogedal\TbiBank\Model;

use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Encryption\EncryptorInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Store\Model\ScopeInterface;

class Environment
{
    public const CONNECTION = 'tbi_settings/autogedal_connection/';
    public const VENDOR_ORIGIN = 'https://ro.tbibank.support';
    public const UAT_ORIGIN = 'https://ro.tbi-uat.online';

    private ScopeConfigInterface $scopeConfig;
    private EncryptorInterface $encryptor;

    public function __construct(ScopeConfigInterface $scopeConfig, EncryptorInterface $encryptor)
    {
        $this->scopeConfig = $scopeConfig;
        $this->encryptor = $encryptor;
    }

    public function isUat(): bool
    {
        $mode = (string) $this->scopeConfig->getValue(self::CONNECTION . 'test_mode');
        if (!in_array($mode, ['', '0', '1'], true)) {
            throw new LocalizedException(__('Invalid TBI environment.'));
        }
        return $mode === '1';
    }

    public function getOrigin(): string
    {
        $path = self::CONNECTION . ($this->isUat() ? 'uat_url' : 'production_url');
        $url = rtrim(trim((string) $this->scopeConfig->getValue($path)), '/');
        if ($url === '') {
            $url = $this->isUat() ? self::UAT_ORIGIN : self::VENDOR_ORIGIN;
        }
        return $this->validateOrigin($url);
    }

    public static function validateOrigin(string $url): string
    {
        $url = rtrim(trim($url), '/');
        $parts = parse_url($url);
        if (!is_array($parts) || ($parts['scheme'] ?? '') !== 'https' || empty($parts['host'])
            || isset($parts['user']) || isset($parts['pass']) || isset($parts['query'])
            || isset($parts['fragment']) || !empty($parts['path'])
            || filter_var($url, FILTER_VALIDATE_URL) === false
        ) {
            throw new LocalizedException(__('The TBI URL must be an HTTPS origin without a path or credentials.'));
        }
        return $url;
    }

    public function replaceVendorOrigin(string $url): string
    {
        if ($url !== self::VENDOR_ORIGIN && strpos($url, self::VENDOR_ORIGIN . '/') !== 0) {
            return $url;
        }
        return $this->getOrigin() . substr($url, strlen(self::VENDOR_ORIGIN));
    }

    public function getEffectivePath(string $path): string
    {
        if (!$this->isUat()) {
            return $path;
        }
        $general = 'tbi_settings/general_settings/';
        $labels = 'tbi_settings/label_settings/';
        if (strpos($path, $general) === 0) {
            return 'tbi_settings/uat_settings/' . substr($path, strlen($general));
        }
        if (strpos($path, $labels) === 0) {
            return 'tbi_settings/uat_label_settings/' . substr($path, strlen($labels));
        }
        return $path;
    }

    public function getUatValue(string $path)
    {
        $value = $this->scopeConfig->getValue($this->getEffectivePath($path));
        if ($path === 'tbi_settings/general_settings/encryption_key' && $value) {
            return $this->decodeKeyValue((string) $value);
        }
        return $value;
    }

    public function decodeKeyValue(string $value): string
    {
        return KeyValue::decode($value, $this->encryptor);
    }

    public function assertUatCredentials(): void
    {
        if (!$this->isUat()) {
            return;
        }
        foreach (['reseller_code', 'reseller_key', 'encryption_key'] as $field) {
            if (trim((string) $this->getUatValue('tbi_settings/general_settings/' . $field)) === '') {
                throw new LocalizedException(__('Configure all TBI UAT credentials before making test requests.'));
            }
        }
    }

    public function getCredentials($storeId = null): array
    {
        $values = [];
        foreach (['reseller_code', 'reseller_key', 'encryption_key'] as $field) {
            $path = 'tbi_settings/general_settings/' . $field;
            $value = $this->isUat()
                ? $this->scopeConfig->getValue($this->getEffectivePath($path))
                : $this->scopeConfig->getValue($path, ScopeInterface::SCOPE_STORE, $storeId);
            $values[$field] = $field === 'encryption_key' ? $this->decodeKeyValue((string) $value) : (string) $value;
            if (trim($values[$field]) === '') {
                throw new LocalizedException(__('Configure all credentials for the selected TBI account.'));
            }
        }
        return $values;
    }

    public function getAccountFingerprint($storeId = null): string
    {
        return hash('sha256', json_encode([$this->getOrigin(), $this->getCredentials($storeId)]));
    }
}
