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

namespace Simplyin\Payment\Observer;

use Magento\Framework\App\Cache\TypeListInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\Config\Storage\WriterInterface;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Message\ManagerInterface;
use Psr\Log\LoggerInterface;
use Simplyin\Payment\Cron\SyncPluginConfig;
use Simplyin\Payment\Model\Auth\RsaRegistrar;

/**
 * Runs the full plugin config sync immediately when the Simply.IN admin section is saved (i.e. when
 * the merchant enters/changes the API key). Without this, RSA registers lazily on the first
 * checkout call but the webhook signing secret only arrives on the next cron tick (up to 5 min) —
 * a window in which inbound payment webhooks are rejected. Forcing the sync on save closes it:
 * RSA registers and the webhook secret is stored right away.
 */
class ConfigChangeSync implements ObserverInterface
{
    private const CONFIG_PATH_PLUGIN_CONFIG_SYNCED = 'payment/simplyin_payment/plugin_config_synced';

    /**
     * @var WriterInterface
     */
    private $configWriter;

    /**
     * @var TypeListInterface
     */
    private $cacheTypeList;

    /**
     * @var SyncPluginConfig
     */
    private $syncPluginConfig;

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var ManagerInterface
     */
    private $messageManager;

    /**
     * @var RsaRegistrar
     */
    private $rsaRegistrar;

    /**
     * @param WriterInterface $configWriter
     * @param TypeListInterface $cacheTypeList
     * @param SyncPluginConfig $syncPluginConfig
     * @param LoggerInterface $logger
     * @param ManagerInterface $messageManager
     * @param RsaRegistrar $rsaRegistrar
     */
    public function __construct(
        WriterInterface $configWriter,
        TypeListInterface $cacheTypeList,
        SyncPluginConfig $syncPluginConfig,
        LoggerInterface $logger,
        ManagerInterface $messageManager,
        RsaRegistrar $rsaRegistrar
    ) {
        $this->configWriter = $configWriter;
        $this->cacheTypeList = $cacheTypeList;
        $this->syncPluginConfig = $syncPluginConfig;
        $this->logger = $logger;
        $this->messageManager = $messageManager;
        $this->rsaRegistrar = $rsaRegistrar;
    }

    /**
     * Re-sync SimplyIN plugin config immediately when an admin saves the module's config section.
     *
     * @param Observer $observer
     * @return void
     */
    public function execute(Observer $observer): void
    {
        try {
            // Reset the "already synced" flag (and refresh the config cache so the sync sees it) so
            // SyncPluginConfig runs its full flow now instead of short-circuiting.
            $this->configWriter->save(
                self::CONFIG_PATH_PLUGIN_CONFIG_SYNCED,
                '0',
                ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
                0
            );
            $this->cacheTypeList->cleanType('config');

            $this->syncPluginConfig->execute();

            // Surface the RSA registration outcome to the admin who just saved the section. This path
            // is adminhtml-only (see adminhtml/events.xml), so the message never reaches the storefront
            // or the API flow — no per-request noise. ensureRegistered() is idempotent: execute() above
            // already attempted it, so this call only reports the resulting state (no second handshake).
            if ($this->rsaRegistrar->hasApiKey()) {
                if ($this->rsaRegistrar->ensureRegistered()) {
                    $this->messageManager->addSuccessMessage(
                        __('Simply.IN: secure connection established — RSA request signing is active.')
                    );
                } else {
                    $this->messageManager->addErrorMessage(
                        __('Simply.IN: could not establish the secure connection. Verify the API key — the plugin will keep retrying automatically.')
                    );
                }
            }
        } catch (\Throwable $e) {
            // Best-effort: the recurring cron remains the backstop.
            $this->logger->error('SimplyIN: config-change sync failed — ' . $e->getMessage());
            $this->messageManager->addErrorMessage(
                __('Simply.IN: configuration sync failed. It will be retried automatically by the background job.')
            );
        }
    }
}
