<?php
/**
 * Mirasvit
 *
 * This source file is subject to the Mirasvit Software License, which is available at https://mirasvit.com/license/.
 * Do not edit or add to this file if you wish to upgrade the to newer versions in the future.
 * If you wish to customize this module for your needs.
 * Please refer to http://www.magentocommerce.com for more information.
 *
 * @category  Mirasvit
 * @package   mirasvit/module-cache-warmer
 * @version   1.11.13
 * @copyright Copyright (C) 2026 Mirasvit (https://mirasvit.com/)
 */



namespace Mirasvit\CacheWarmer\Cron;

use Magento\Framework\Lock\LockManagerInterface;
use Mirasvit\CacheWarmer\Api\Data\JobInterface;
use Mirasvit\CacheWarmer\Api\Repository\JobRepositoryInterface;
use Mirasvit\CacheWarmer\Api\Service\JobServiceInterface;
use Mirasvit\CacheWarmer\Helper\LockManager;
use Mirasvit\CacheWarmer\Logger\Logger;
use Mirasvit\CacheWarmer\Model\Config;

class RunJob
{
    private $jobRepository;

    private $jobService;

    private $config;

    private $lockManager;

    private $logger;

    public function __construct(
        JobRepositoryInterface $jobRepository,
        JobServiceInterface $jobService,
        LockManager $lockManager,
        Config $config,
        Logger $logger
    ) {
        $this->jobRepository = $jobRepository;
        $this->jobService    = $jobService;
        $this->lockManager   = $lockManager;
        $this->config        = $config;
        $this->logger        = $logger;
    }

    const MAX_FAILED_JOBS = 3;

    /**
     * @return void
     */
    public function execute()
    {
        if (!$this->config->isEnabled()) {
            return;
        }

        $lockName = 'mst-cache-warmer.cli.lock';

        if (!$this->lockManager->lock($lockName)) {
            return;
        }

        try {
            $collection = $this->jobRepository->getCollection();
            $collection->addFieldToFilter(JobInterface::STARTED_AT, ['null' => true]);

            $failedJobs = 0;

            foreach ($collection as $job) {
                try {
                    $this->jobService->run($job, 'cron');
                } catch (\Exception $e) {
                    $this->logger->error('Job failed: ' . $e->getMessage(), [
                        'trace' => $e->getTraceAsString(),
                    ]);

                    try {
                        $job->setStatus(JobInterface::STATUS_ERROR)
                            ->setFinishedAt((new \DateTime())->format('Y-m-d H:i:s'));

                        $info = $job->getInfo();
                        $info['Error'] = $e->getMessage();
                        $job->setInfo($info);

                        $this->jobRepository->save($job);
                    } catch (\Exception $saveException) {
                        $this->logger->error('Failed to save job error status: ' . $saveException->getMessage());
                    }

                    $failedJobs++;

                    if ($failedJobs >= self::MAX_FAILED_JOBS) {
                        break;
                    }
                }
            }
        } finally {
            $this->lockManager->unlock($lockName);
        }
    }
}
