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

namespace Simplyin\Payment\Model\Auth;

use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\ScopeInterface;
use Psr\Log\LoggerInterface;
use Simplyin\Payment\Http\SigningCurlClient;
use Simplyin\Payment\Model\Config\EnvironmentConfig;

/**
 * Best-effort backend revoke of the currently registered RSA public key.
 *
 * Called right before local RSA material is wiped (module uninstall — see
 * {@see \Simplyin\Payment\Setup\Uninstall}), so removing the plugin from a shop does not leave an
 * orphaned, still-active signing credential registered on the backend forever.
 *
 * Signed with the same RSA request-signing mechanism already used for the runtime API calls (see
 * {@see SigningCurlClient}) — the backend only accepts this call from a caller that can prove
 * possession of the currently registered private key.
 *
 * Never throws: any failure (missing config, network, non-2xx response) is caught and logged, so a
 * caller doing local cleanup can proceed unconditionally afterwards.
 */
class RsaRevoker
{
    private const REVOKE_ENDPOINT = 'plugin-sync/revokePluginPublicKeyRegistration';

    /**
     * @var RsaSigner
     */
    private RsaSigner $signer;

    /**
     * @var SigningCurlClient
     */
    private SigningCurlClient $curl;

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

    /**
     * @var EnvironmentConfig
     */
    private EnvironmentConfig $environmentConfig;

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

    /**
     * @param RsaSigner $signer
     * @param SigningCurlClient $curl
     * @param ScopeConfigInterface $scopeConfig
     * @param EnvironmentConfig $environmentConfig
     * @param LoggerInterface $logger
     */
    public function __construct(
        RsaSigner $signer,
        SigningCurlClient $curl,
        ScopeConfigInterface $scopeConfig,
        EnvironmentConfig $environmentConfig,
        LoggerInterface $logger
    ) {
        $this->signer = $signer;
        $this->curl = $curl;
        $this->scopeConfig = $scopeConfig;
        $this->environmentConfig = $environmentConfig;
        $this->logger = $logger;
    }

    /**
     * Ask the backend to revoke the currently registered RSA public key.
     *
     * No-op when nothing is registered locally, or when the request could not be RSA-signed anyway
     * (OpenSSL unavailable) — nothing usable to send. Best-effort: any failure is caught and
     * logged, never thrown.
     *
     * @return void
     */
    public function revoke(): void
    {
        if (!$this->signer->isActive()) {
            return;
        }

        $base = rtrim($this->environmentConfig->getApiBaseUrl(), '/');
        if ($base === '') {
            $this->logger->warning('SimplyIN RSA: no API base URL configured, cannot revoke registration');
            return;
        }

        try {
            // Staging the (empty) API key header is what makes SigningCurlClient treat this as an
            // authenticated request: it strips the header and RSA-signs instead, the same mechanism
            // already used for /plugin-sync/info and /plugin-sync/sync. Origin is required on every
            // plugin-sync/* call — the backend validates it against the merchant's registered
            // domain and rejects the request outright without it (see RsaRegistrar::getOrigin()).
            $this->curl->setHeaders([
                'Content-Type' => 'application/json',
                'Origin' => $this->getOrigin(),
                'X-Auth-Merchant-Api-Key' => '',
            ]);
            $this->curl->post($base . '/' . self::REVOKE_ENDPOINT, '');

            $statusCode = $this->curl->getStatus();
            if ($statusCode < 200 || $statusCode >= 300) {
                $this->logger->warning('SimplyIN RSA: revoke registration request rejected', [
                    'statusCode' => $statusCode,
                ]);
                return;
            }

            $this->logger->info('SimplyIN RSA: registration revoked on backend');
        } catch (\Throwable $e) {
            $this->logger->warning('SimplyIN RSA: revoke registration failed — ' . $e->getMessage());
        }
    }

    /**
     * Shop origin, sent with the revoke request.
     *
     * Mirrors RsaRegistrar::getOrigin() (no StoreManager fallback, unlike ApiTransport::getOrigin())
     * — every authenticated backend call carries this header.
     *
     * @return string
     */
    private function getOrigin(): string
    {
        $baseUrl = (string)$this->scopeConfig->getValue('web/secure/base_url', ScopeInterface::SCOPE_STORE);
        $baseUrl = (string)preg_replace('#/index\.php/?#', '/', $baseUrl);

        return rtrim($baseUrl, '/');
    }
}
