<?php
/**
 * Copyright © Simplyin. All rights reserved.
 */
declare(strict_types=1);

namespace Simplyin\HyvaPayment\ViewModel;

use Magento\Framework\View\Element\Block\ArgumentInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\ScopeInterface;
use Magento\Framework\View\Asset\Repository as AssetRepository;
use Magento\Checkout\Model\Session as CheckoutSession;
use Magento\Framework\Locale\ResolverInterface;
use Simplyin\Payment\Service\PaymentMethodAvailability;

/**
 * PaymentConfig ViewModel
 *
 * Provides payment method configuration data to Hyva templates including
 * payment method types, logos, currency-based filtering (BLIK), and display settings.
 *
 * This ViewModel is used by the Payment_Method_Renderer to display the Simplyin
 * payment option in the Hyva checkout payment step.
 *
 * @see Requirements 8.1, 8.3
 */
class PaymentConfig implements ArgumentInterface
{
    /**
     * Configuration paths from Simplyin_Payment module
     */
    private const XML_PATH_ACTIVE = 'payment/simplyin_payment/active';
    private const XML_PATH_DEFAULT_CREATE_ACCOUNT_CHECKED = 'payment/simplyin_payment/default_create_account_checked';
    private const XML_PATH_GDPR_URL_EN = 'payment/simplyin_payment/gdpr_url_en';
    private const XML_PATH_GDPR_URL_PL = 'payment/simplyin_payment/gdpr_url_pl';
    private const XML_PATH_TERMS_B2C_URL_EN = 'payment/simplyin_payment/terms_b2c_url_en';
    private const XML_PATH_TERMS_B2C_URL_PL = 'payment/simplyin_payment/terms_b2c_url_pl';
    private const XML_PATH_TERMS_B2B_URL_EN = 'payment/simplyin_payment/terms_b2b_url_en';
    private const XML_PATH_TERMS_B2B_URL_PL = 'payment/simplyin_payment/terms_b2b_url_pl';

    /**
     * Payment method type constants
     */
    public const PAYMENT_TYPE_SAVED_CARD = 'saved_card';
    public const PAYMENT_TYPE_NEW_CARD = 'new_card';
    public const PAYMENT_TYPE_BLIK = 'blik';
    public const PAYMENT_TYPE_BANK_TRANSFER = 'bank_transfer';

    /**
     * @var ScopeConfigInterface
     */
    private ScopeConfigInterface $scopeConfig;

    /**
     * @var AssetRepository
     */
    private AssetRepository $assetRepository;

    /**
     * @var CheckoutSession
     */
    private CheckoutSession $checkoutSession;

    /**
     * @var ResolverInterface
     */
    private ResolverInterface $localeResolver;

    /**
     * @var PaymentMethodAvailability
     */
    private PaymentMethodAvailability $paymentMethodAvailability;

    /**
     * Constructor
     *
     * @param ScopeConfigInterface $scopeConfig
     * @param AssetRepository $assetRepository
     * @param CheckoutSession $checkoutSession
     * @param ResolverInterface $localeResolver
     * @param PaymentMethodAvailability $paymentMethodAvailability
     */
    public function __construct(
        ScopeConfigInterface $scopeConfig,
        AssetRepository $assetRepository,
        CheckoutSession $checkoutSession,
        ResolverInterface $localeResolver,
        PaymentMethodAvailability $paymentMethodAvailability
    ) {
        $this->scopeConfig = $scopeConfig;
        $this->assetRepository = $assetRepository;
        $this->checkoutSession = $checkoutSession;
        $this->localeResolver = $localeResolver;
        $this->paymentMethodAvailability = $paymentMethodAvailability;
    }

    /**
     * Get available payment method types
     *
     * Returns an array of payment method type definitions with their
     * display names, logos, and configuration.
     *
     * @see Requirement 8.3
     * @return array<string, array{type: string, name: string, logo: string, enabled: bool}>
     */
    public function getPaymentMethodTypes(): array
    {
        $isBlikAvailable = $this->isBlikAvailable();

        return [
            self::PAYMENT_TYPE_SAVED_CARD => [
                'type' => self::PAYMENT_TYPE_SAVED_CARD,
                'name' => __('Saved Card'),
                'logo' => $this->getCardLogoUrl(),
                'enabled' => true,
            ],
            self::PAYMENT_TYPE_NEW_CARD => [
                'type' => self::PAYMENT_TYPE_NEW_CARD,
                'name' => __('Add New Card'),
                'logo' => $this->getCardLogoUrl(),
                'enabled' => true,
            ],
            self::PAYMENT_TYPE_BLIK => [
                'type' => self::PAYMENT_TYPE_BLIK,
                'name' => __('BLIK'),
                'logo' => $this->getBlikLogoUrl(),
                'enabled' => $isBlikAvailable,
            ],
            self::PAYMENT_TYPE_BANK_TRANSFER => [
                'type' => self::PAYMENT_TYPE_BANK_TRANSFER,
                'name' => __('Bank Transfer'),
                'logo' => $this->getBankTransferLogoUrl(),
                'enabled' => true,
            ],
        ];
    }

    /**
     * Check if BLIK payment is available
     *
     * BLIK is only available for PLN currency.
     *
     * @see Requirement 8.4
     * @return bool True if BLIK is available
     */
    public function isBlikAvailable(): bool
    {
        $currencyCode = $this->getCurrentCurrencyCode();
        return strtoupper($currencyCode) === 'PLN';
    }

    /**
     * Get current quote currency code
     *
     * @return string Currency code (e.g., 'PLN', 'EUR')
     */
    public function getCurrentCurrencyCode(): string
    {
        $quote = $this->checkoutSession->getQuote();
        return $quote ? (string) $quote->getQuoteCurrencyCode() : 'PLN';
    }

    /**
     * Get Simplyin logo URL
     *
     * @return string URL to the Simplyin logo
     */
    public function getSimplyinLogoUrl(): string
    {
        return $this->assetRepository->getUrl('Simplyin_Payment::images/simplyin-logo.svg');
    }

    /**
     * Get P24 (Przelewy24) logo URL
     *
     * @return string URL to the P24 logo
     */
    public function getP24LogoUrl(): string
    {
        return $this->assetRepository->getUrl('Simplyin_Payment::images/p24.svg');
    }

    /**
     * Get card payment logo URL
     *
     * @return string URL to the card logo
     */
    public function getCardLogoUrl(): string
    {
        return $this->assetRepository->getUrl('Simplyin_Payment::images/card-brands.svg');
    }

    /**
     * Get BLIK logo URL
     *
     * @return string URL to the BLIK logo
     */
    public function getBlikLogoUrl(): string
    {
        return $this->assetRepository->getUrl('Simplyin_Payment::images/blik.svg');
    }

    /**
     * Get bank transfer logo URL
     *
     * @return string URL to the bank transfer logo
     */
    public function getBankTransferLogoUrl(): string
    {
        return $this->assetRepository->getUrl('Simplyin_Payment::images/bank-transfer.svg');
    }

    /**
     * Get card brand logo URL
     *
     * @param string $brand Card brand (visa, mastercard, amex, etc.)
     * @return string URL to the card brand logo
     */
    public function getCardBrandLogoUrl(string $brand): string
    {
        $brand = strtolower($brand);
        return $this->assetRepository->getUrl('Simplyin_Payment::images/cards/' . $brand . '.svg');
    }

    /**
     * Check if Simplyin payment is enabled
     *
     * @return bool True if Simplyin payment is enabled
     */
    public function isSimplyinEnabled(): bool
    {
        return (bool) $this->scopeConfig->getValue(
            self::XML_PATH_ACTIVE,
            ScopeInterface::SCOPE_STORE
        );
    }

    /**
     * Check if the merchant has at least one SimplyIN payment method configured
     *
     * Backed by the shared availability service (fail-closed; returns false
     * on a successful empty result or on any error/exception/unauthenticated
     * response). Used by the checkout templates to suppress the SimplyIN branding
     * when no payment method is configured.
     *
     * @return bool True if at least one payment method is available
     */
    public function hasAvailablePaymentMethods(): bool
    {
        return $this->paymentMethodAvailability->hasAvailablePaymentMethods();
    }

    /**
     * Get default state for new account checkbox
     *
     * @return bool True if checkbox should be checked by default
     */
    public function isNewAccountCheckboxDefault(): bool
    {
        // Config value 1 = "checkbox is NOT selected by default" → return false
        // Config value 0 = checkbox IS selected by default → return true
        $configValue = (bool) $this->scopeConfig->getValue(
            self::XML_PATH_DEFAULT_CREATE_ACCOUNT_CHECKED,
            ScopeInterface::SCOPE_STORE
        );
        return !$configValue;
    }

    /**
     * Check if current locale is Polish
     *
     * @return bool True if Polish locale
     */
    public function isPolishLocale(): bool
    {
        $locale = $this->localeResolver->getLocale();
        return strpos($locale, 'pl_') === 0 || $locale === 'pl';
    }

    /**
     * Get current store locale
     *
     * @return string Locale code (e.g., 'pl_PL', 'en_US')
     */
    public function getStoreLocale(): string
    {
        return $this->localeResolver->getLocale();
    }

    /**
     * Get GDPR/Privacy Policy URL (locale-agnostic)
     *
     * @return string URL to privacy policy
     */
    public function getGdprUrl(): string
    {
        $url = $this->scopeConfig->getValue(self::XML_PATH_GDPR_URL_PL, ScopeInterface::SCOPE_STORE);
        if (empty($url)) {
            $url = $this->scopeConfig->getValue(self::XML_PATH_GDPR_URL_EN, ScopeInterface::SCOPE_STORE);
        }

        if (empty($url)) {
            return 'https://simply.in/privacy-policy/';
        }

        return (string) $url;
    }

    /**
     * Get Terms B2C URL (locale-agnostic)
     *
     * @return string URL to B2C terms
     */
    public function getTermsB2cUrl(): string
    {
        $url = $this->scopeConfig->getValue(self::XML_PATH_TERMS_B2C_URL_PL, ScopeInterface::SCOPE_STORE);
        if (empty($url)) {
            $url = $this->scopeConfig->getValue(self::XML_PATH_TERMS_B2C_URL_EN, ScopeInterface::SCOPE_STORE);
        }

        if (empty($url)) {
            return 'https://simply.in/terms-b2c/';
        }

        return (string) $url;
    }

    /**
     * Get Terms B2B URL based on locale
     *
     * @return string URL to B2B terms
     */
    public function getTermsB2bUrl(): string
    {
        $isPolish = $this->isPolishLocale();
        $configPath = $isPolish ? self::XML_PATH_TERMS_B2B_URL_PL : self::XML_PATH_TERMS_B2B_URL_EN;
        $url = $this->scopeConfig->getValue($configPath, ScopeInterface::SCOPE_STORE);

        if (empty($url)) {
            return $isPolish
                ? 'https://www.simply.in/terms-b2b'
                : 'https://www.simply.in/en/terms-b2b';
        }

        return (string) $url;
    }

    /**
     * Get regulatory links for payment provider
     *
     * Returns an array of regulatory links (GDPR, Terms) for display
     * in the payment method renderer.
     *
     * @see Requirement 8.7
     * @return array<string, string>
     */
    public function getRegulatoryLinks(): array
    {
        return [
            'gdpr' => $this->getGdprUrl(),
            'termsB2c' => $this->getTermsB2cUrl(),
            'termsB2b' => $this->getTermsB2bUrl(),
        ];
    }

    /**
     * Get payment configuration as JSON
     *
     * Returns all payment configuration as a JSON-encoded string
     * for use in Alpine.js components.
     *
     * @return string JSON-encoded configuration
     */
    public function getConfigJson(): string
    {
        return json_encode([
            'isEnabled' => $this->isSimplyinEnabled(),
            'isBlikAvailable' => $this->isBlikAvailable(),
            'currencyCode' => $this->getCurrentCurrencyCode(),
            'paymentMethodTypes' => $this->getPaymentMethodTypes(),
            'logos' => [
                'simplyin' => $this->getSimplyinLogoUrl(),
                'p24' => $this->getP24LogoUrl(),
                'card' => $this->getCardLogoUrl(),
                'blik' => $this->getBlikLogoUrl(),
                'bankTransfer' => $this->getBankTransferLogoUrl(),
            ],
            'regulatoryLinks' => $this->getRegulatoryLinks(),
            'newAccountCheckboxDefault' => $this->isNewAccountCheckboxDefault(),
            'isPolishLocale' => $this->isPolishLocale(),
            'storeLocale' => $this->getStoreLocale(),
        ], JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
    }

    /**
     * Format card display for saved cards
     *
     * Returns a formatted string for displaying saved card information.
     *
     * @param string $last4 Last 4 digits of card number
     * @param string $brand Card brand (visa, mastercard, etc.)
     * @param string|null $expiryMonth Expiry month (optional)
     * @param string|null $expiryYear Expiry year (optional)
     * @return string Formatted card display string
     */
    public function formatCardDisplay(
        string $last4,
        string $brand,
        ?string $expiryMonth = null,
        ?string $expiryYear = null
    ): string {
        $brandDisplay = ucfirst(strtolower($brand));
        $display = sprintf('%s •••• %s', $brandDisplay, $last4);

        if ($expiryMonth !== null && $expiryYear !== null) {
            $display .= sprintf(' (%s/%s)', $expiryMonth, $expiryYear);
        }

        return $display;
    }

    /**
     * Get supported card brands
     *
     * Returns an array of supported card brands with their display names.
     *
     * @return array<string, string>
     */
    public function getSupportedCardBrands(): array
    {
        return [
            'visa' => 'Visa',
            'mastercard' => 'Mastercard',
            'amex' => 'American Express',
            'discover' => 'Discover',
            'diners' => 'Diners Club',
            'jcb' => 'JCB',
            'unionpay' => 'UnionPay',
        ];
    }
}
