<?php
namespace TbiBank\FusionPay\Cron;

use Magento\AdminNotification\Model\InboxFactory;
use Magento\Framework\App\CacheInterface;
use Magento\Framework\HTTP\Client\Curl;
use Magento\Framework\Module\ModuleListInterface;
use Magento\Framework\Serialize\SerializerInterface;
use TbiBank\FusionPay\Helper\Data as FusionPayHelper;
use TbiBank\FusionPay\Logger\FusionPayLogger;

/**
 * Checks the tbi platform for a newer plugin version and raises an admin notification.
 *
 * Previously an observer bound to controller_action_predispatch, which instantiated Curl,
 * the helper and the logger on EVERY admin request only to hit a 24h cache guard and return
 * (partner review item 2). The check is time-based, not request-based, so it belongs on the
 * schedule instead: fusionpay_update_checker in etc/crontab.xml runs it once a day.
 */
class CheckForUpdate
{
    /**
     * Cache key and lifetime retained from the observer implementation, so an install that
     * already checked recently does not re-check immediately after upgrading.
     */
    public const CACHE_KEY = 'fusionpay_update_check';
    public const CACHE_LIFETIME = 86400; // 24 hours in seconds

    private const MODULE_CODE = 'TbiBank_FusionPay';

    protected $moduleList;
    protected $curl;
    protected $logger;
    protected $fusionPayHelper;
    protected $cache;
    protected $serializer;
    protected $inboxFactory;

    public function __construct(
        ModuleListInterface $moduleList,
        Curl $curl,
        FusionPayLogger $logger,
        FusionPayHelper $fusionPayHelper,
        CacheInterface $cache,
        SerializerInterface $serializer,
        InboxFactory $inboxFactory
    ) {
        $this->moduleList = $moduleList;
        $this->curl = $curl;
        $this->logger = $logger;
        $this->fusionPayHelper = $fusionPayHelper;
        $this->cache = $cache;
        $this->serializer = $serializer;
        $this->inboxFactory = $inboxFactory;
    }

    /**
     * Run the version check.
     *
     * @return void
     */
    public function execute()
    {
        // The endpoint is resolved here rather than in the constructor so the cron job does not
        // read configuration while the object graph is still being built.
        $endpoint = $this->fusionPayHelper->getConstValue('TBI_PLATFORM_URL')
            . '/fusion-pay-ro-tbi/magento2/info.json';

        if ($this->checkedRecently()) {
            return;
        }

        $currentVersion = $this->moduleList->getOne(self::MODULE_CODE)['setup_version'] ?? null;

        try {
            $this->curl->setHeaders(['Accept' => 'application/json']);
            $this->curl->setOption(CURLOPT_CONNECTTIMEOUT, 2);
            $this->curl->setOption(CURLOPT_TIMEOUT, 3);
            $this->curl->get($endpoint);
            $response = $this->curl->getBody();
        } catch (\Throwable $e) {
            $this->logger->error('Update check failed: ' . $e->getMessage());
            return;
        }

        if (!$response) {
            $this->logger->error('No response from API call to ' . $endpoint);
            return;
        }

        $this->logger->info(
            'Successful API call to ' . $endpoint . ' response: ' . preg_replace('/\s+/', '', $response)
        );

        $apiData = json_decode($response, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            $this->logger->error('Error decoding API response from ' . $endpoint);
            return;
        }

        $latestVersion = $apiData['version'] ?? 'unknown';

        if ($currentVersion !== null && version_compare($currentVersion, $latestVersion, '<')) {
            $this->inboxFactory->create()->addCritical(
                __('New version of Fusion Pay RO available'),
                __('Please update to version %1.', $latestVersion)
            );
        }

        $this->cache->save(
            $this->serializer->serialize(['next_check' => time() + self::CACHE_LIFETIME]),
            self::CACHE_KEY,
            [],
            self::CACHE_LIFETIME
        );
    }

    /**
     * Whether a check already ran inside the cache lifetime.
     *
     * @return bool
     */
    private function checkedRecently()
    {
        $cachedData = $this->cache->load(self::CACHE_KEY);
        if (!$cachedData) {
            return false;
        }

        $data = $this->serializer->unserialize($cachedData);

        return isset($data['next_check']) && time() < $data['next_check'];
    }
}
