<?php

/**
 * Copyright 2024-2025 Simply.IN Sp. z o.o.
 *
 * NOTICE OF LICENSE
 *
 * Licensed under the EUPL-1.2 or later.
 * You may not use this work except in compliance with the Licence.
 *
 * Copy of the Licence is available at:
 * https://joinup.ec.europa.eu/software/page/eupl
 * It is bundled with this package in the file LICENSE.txt
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the Licence is distributed on an as is basis,
 * without warranties or conditions of any kind, either express or implied.
 * Check the Licence for the specific language governing permissions
 * and limitations under the License.
 *
 * @author   Simply.IN Sp. z o.o.
 * @copyright 2024-2025 Simply.IN Sp. z o.o.
 * @license   https://joinup.ec.europa.eu/software/page/eupl
 */

declare(strict_types=1);

namespace SimplyIn\Checkout;

use SimplyIn\Session\SimplyInSessionInterface;

if (!defined('_PS_VERSION_')) {
    exit;
}

final class PaymentSelectionStore
{
    /** @var list<string> */
    private const CARD_KEYS = [
        'simplyin_card_name',
        'simplyin_card_last_digits',
        'simplyin_card_provider',
        'simplyin_card_ott',
        'simplyin_card_save',
    ];

    private const MAX_FIELD_LENGTH = 2048;

    public function __construct(private readonly SimplyInSessionInterface $session)
    {
    }

    public function storeSelection(
        string $paymentType,
        string $paymentId,
        string $paymentProvider,
        string $providerImage,
        string $logo,
        string $cardName = '',
        string $cardLastDigits = '',
        string $cardProvider = '',
        string $cardOtt = '',
        bool $cardSave = false,
    ): void {
        if (preg_match('/^\d{4}$/', $cardLastDigits) !== 1) {
            $cardLastDigits = '';
        }

        $this->session->set('simplyin_payment_type', $this->cap($paymentType));
        $this->session->set('simplyin_payment_id', $this->cap($paymentId));
        $this->session->set('simplyin_payment_provider', $this->cap($paymentProvider));
        $this->session->set('simplyin_payment_image', $this->cap($providerImage));
        $this->session->set('simplyin_payment_logo', $this->cap($logo));

        if ($paymentType === 'add-card') {
            // Read before overwriting below: this is the only way to tell "just marked to be
            // saved" from "already was, selected again" - re-rendering the same form, switching
            // methods and back, or a retry re-issuing the prior selection must not pay the
            // invalidation cost below a second time for a card that was already accounted for.
            $wasAlreadyMarkedToSave = (bool) $this->session->get('simplyin_card_save');

            $this->session->set('simplyin_card_name', $this->cap($cardName));
            $this->session->set('simplyin_card_last_digits', $cardLastDigits);
            $this->session->set('simplyin_card_provider', $this->cap($cardProvider));
            $this->session->set('simplyin_card_ott', $this->cap($cardOtt));
            $this->session->set('simplyin_card_save', $cardSave ? 1 : 0);

            // Found closing the payment retry loop: a card marked to be saved here becomes a
            // retrievable Simply.IN method for THIS SAME authToken - but PaymentMethodsProvider
            // caches that lookup for 120 seconds, keyed only on the authToken, with no notion of
            // "a save just happened". A shopper who adds a card, has this attempt declined and
            // retries within that window would see the pay-again paywall built from the SAME stale
            // pre-save cache entry the original checkout page already wrote - offering only
            // add-a-card and BLIK again, never the card they just tried to save. Invalidating here,
            // at the one point that actually changes what the next lookup should return, is what
            // lets the retry paywall's very next read go to SIN.CORE instead of the stale cache -
            // only on the false→true transition, so re-selecting an already-saved card does not
            // force every later read to skip a cache that is still accurate.
            if ($cardSave && !$wasAlreadyMarkedToSave) {
                $this->session->unset('simplyin_pm_cache');
            }

            return;
        }

        if ($paymentType === 'card') {
            $this->session->set('simplyin_card_name', $this->cap($cardName));
            $this->session->set('simplyin_card_last_digits', $cardLastDigits);
            $this->session->set('simplyin_card_provider', $this->cap($cardProvider));
            $this->session->unset('simplyin_card_ott');
            $this->session->unset('simplyin_card_save');

            return;
        }

        $this->session->unset(self::CARD_KEYS);
    }

    public function storeBlikCode(string $code): void
    {
        if (preg_match('/^\d{6}$/', $code) !== 1) {
            $this->clearBlikCode();

            return;
        }

        $this->session->set('simplyin_payment_blik', $code);
    }

    private function cap(string $value): string
    {
        return substr($value, 0, self::MAX_FIELD_LENGTH);
    }

    public function clearBlikCode(): void
    {
        $this->session->unset('simplyin_payment_blik');
    }
}
