<?php

namespace App\Monitor\Framework\Scheduler;

use App\Monitor\Action\Command\MonitorMovieCommand;
use App\Monitor\Action\Command\MonitorTvEpisodeCommand;
use App\Monitor\Action\Command\MonitorTvSeasonCommand;
use App\Monitor\Action\Command\MonitorTvShowCommand;
use App\Monitor\Framework\Repository\MonitorRepository;
use Carbon\Carbon;
use Psr\Log\LoggerInterface;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Scheduler\Attribute\AsCronTask;

#[AsCronTask('0 * * * *', schedule: 'monitor')]
class MonitorDispatcher
{
    public function __construct(
        private readonly LoggerInterface $logger,
        private readonly MonitorRepository $monitorRepository,
        private readonly MessageBusInterface $bus,
    ) {}

    public function __invoke() {
        $this->logger->info('[MonitorDispatcher] Executing MonitorDispatcher');

        $this->cleanupStuckMonitors();

        $monitorHandlers = [
            'movie' => MonitorMovieCommand::class,
            'tvepisode' => MonitorTvEpisodeCommand::class,
            'tvseason' => MonitorTvSeasonCommand::class,
            'tvshows' => MonitorTvShowCommand::class,
        ];

        $monitors = $this->monitorRepository->findBy(['status' => ['New', 'Active']]);

        foreach ($monitors as $monitor) {
            $monitor->setStatus('In Progress');
            $this->monitorRepository->getEntityManager()->flush();

            $command = $monitorHandlers[$monitor->getMonitorType()];
            $this->logger->info('[MonitorDispatcher] Dispatching ' . $command . ' for ' . $monitor->getTitle());
            $this->bus->dispatch(new $command($monitor->getId()));
        }
    }

    private function cleanupStuckMonitors(): void
    {
        $hoursStuck = 4;
        $monitors = $this->monitorRepository->findBy(['status' => 'In Progress']);
        foreach ($monitors as $monitor) {
            // Reset the status to active so it will be executed again
            if ($monitor->getLastSearch()->diffInHours(Carbon::today()) > $hoursStuck) {
                $this->logger->info('[MonitorDispatcher] Cleaning up monitor: ' . $monitor->getId() . ' (' . $monitor->getTitle() . '), resetting status to \'Active\' from \''. $monitor->getStatus() .'\' after being stuck for ' . $hoursStuck  . ' hours.');
                $monitor->setStatus('Active');
            }
        }
        $this->monitorRepository->getEntityManager()->flush();
    }
}
