<?php

declare(strict_types=1);

namespace KupShop\SynchronizationBundle\Scheduler;

use KupShop\KupShopBundle\Util\System\PathFinder;
use KupShop\SynchronizationBundle\Scheduler\Message\SynchronizationJobMessage;
use KupShop\SynchronizationBundle\Util\SynchronizationJobProvider;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\Store\FlockStore;
use Symfony\Component\Scheduler\Attribute\AsSchedule;
use Symfony\Component\Scheduler\RecurringMessage;
use Symfony\Component\Scheduler\Schedule;
use Symfony\Component\Scheduler\ScheduleProviderInterface;

/**
 * Synchronization schedule.
 *
 * Use `symfony messenger:consume scheduler_synchronization -vv` to run schedule
 * Use `symfony debug:scheduler` to list all registered schedules
 */
#[AsSchedule(name: 'synchronization')]
class SynchronizationSchedule implements ScheduleProviderInterface
{
    private ?Schedule $schedule = null;

    public function __construct(
        private readonly SynchronizationJobProvider $provider,
        private readonly EventDispatcherInterface $eventDispatcher,
    ) {
    }

    public function getSchedule(): Schedule
    {
        if ($this->schedule === null) {
            $output = new ConsoleOutput();
            // create schedule
            $this->schedule = (new Schedule($this->eventDispatcher))
                ->before(function () use ($output) {
                    $output->writeln('---------------------------------------');
                })
                // add lock, so deploy of multiple synchronization workers is possible
                ->lock($this->getLockFactory()->createLock('scheduler-synchronization'));

            // register all collected sync jobs as RecurringMessage
            foreach ($this->provider->getJobs() as $job) {
                $this->schedule->add(
                    RecurringMessage::cron($job->cronExpression, new SynchronizationJobMessage($job->id))
                );
            }
        }

        return $this->schedule;
    }

    private function getLockFactory(): LockFactory
    {
        return new LockFactory(
            new FlockStore(PathFinder::getService()->getTmpDir())
        );
    }
}
