<?php

namespace App\Monitor\Action\Handler;

use App\Download\Action\Command\DownloadMediaCommand;
use App\Monitor\Action\Command\MonitorMovieCommand;
use App\Monitor\Action\Result\MonitorMovieResult;
use App\Monitor\Action\Result\MonitorTvEpisodeResult;
use App\Monitor\Framework\Repository\MonitorRepository;
use App\Monitor\Service\MonitorOptionEvaluator;
use App\Tmdb\Tmdb;
use App\Torrentio\Action\Command\GetTvShowOptionsCommand;
use App\Torrentio\Action\Handler\GetTvShowOptionsHandler;
use Carbon\Carbon;
use DateTimeImmutable;
use Doctrine\ORM\EntityManagerInterface;
use OneToMany\RichBundle\Contract\CommandInterface;
use OneToMany\RichBundle\Contract\HandlerInterface;
use OneToMany\RichBundle\Contract\ResultInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Messenger\MessageBusInterface;

/** @implements HandlerInterface<MonitorMovieCommand> */
readonly class MonitorTvEpisodeHandler implements HandlerInterface
{
    public function __construct(
        private GetTvShowOptionsHandler $getTvShowOptionsHandler,
        private MonitorOptionEvaluator $monitorOptionEvaluator,
        private EntityManagerInterface $entityManager,
        private MessageBusInterface $bus,
        private LoggerInterface $logger,
        private MonitorRepository $monitorRepository,
        private Tmdb $tmdb,
    ) {}

    public function handle(CommandInterface $command): ResultInterface
    {
        $this->logger->info('> [MonitorTvEpisodeHandler] Executing MonitorTvEpisodeHandler');
        $monitor = $this->monitorRepository->find($command->movieMonitorId);

        $episodeData = $this->tmdb->episodeDetails($monitor->getTmdbId(), $monitor->getSeason(), $monitor->getEpisode());
        if (Carbon::createFromTimestamp($episodeData->episodeAirDate) > Carbon::now()) {
            $this->logger->info('> [MonitorTvEpisodeHandler] Episode has not aired yet, skipping for now');
            return new MonitorTvEpisodeResult(
                status: 'OK',
                result: [
                    'message' => 'No change',
                    'monitor' => $monitor,
                ]
            );
        }

        $monitor->setStatus('In Progress');
        $this->monitorRepository->getEntityManager()->flush();

        $this->logger->info('> [MonitorTvEpisodeHandler] Searching for "' . $monitor->getTitle() . '" season ' . $monitor->getSeason() . ' episode ' . $monitor->getEpisode() . ' download options');
        $results = $this->getTvShowOptionsHandler->handle(
            new GetTvShowOptionsCommand(
                $monitor->getTmdbId(),
                $monitor->getImdbId(),
                $monitor->getSeason(),
                $monitor->getEpisode()
            )
        );

        $this->logger->info('> [MonitorTvEpisodeHandler] Found ' . count($results->results) . ' download options');

        $result = $this->monitorOptionEvaluator->evaluateOptions($monitor, $results->results);

        if (null !== $result) {
            $this->logger->info('> [MonitorTvEpisodeHandler] 1 matching result found: dispatching DownloadMediaCommand for "' . $result->title . '"');
            $this->bus->dispatch(new DownloadMediaCommand(
                $result->url,
                $monitor->getTitle(),
                $result->filename,
                'tvshows',
                $monitor->getImdbId(),
                $monitor->getUser()->getId(),
            ));
            $monitor->setStatus('Complete');
            $monitor->setDownloadedAt(new DateTimeImmutable());
        } else {
            $this->logger->info('> [MonitorTvEpisodeHandler] 0 matching results found, monitor will run at next interval');
            $monitor->setStatus('Active');
        }

        $monitor->setLastSearch(new DateTimeImmutable());
        $monitor->setSearchCount($monitor->getSearchCount() + 1);
        $this->entityManager->flush();

        return new MonitorTvEpisodeResult(
            status: 'OK',
            result: [
                'monitor' => $monitor,
            ]
        );
    }
}
