<?php

declare(strict_types=1);

namespace App\MessageHandler;

use App\Entity\Device;
use App\Entity\DeviceImageHistory;
use App\Message\AdvanceRotationMessage;
use App\Service\RotationService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;

#[AsMessageHandler]
class AdvanceRotationMessageHandler
{
    public function __construct(
        private readonly EntityManagerInterface $em,
        private readonly RotationService        $rotationService,
        private readonly LoggerInterface        $logger,
    ) {}

    public function __invoke(AdvanceRotationMessage $message): void
    {
        $devices = $this->em->getRepository(Device::class)->findAll();

        foreach ($devices as $device) {
            if (!$this->isDue($device)) {
                $this->logger->debug('rotation.not_due', ['device_id' => $device->getId()]);
                continue;
            }

            $image = $this->rotationService->advance($device);
            if ($image === null) {
                $this->logger->info('rotation.no_ready_images', ['device_id' => $device->getId()]);
            }
        }
    }

    private function isDue(Device $device): bool
    {
        if ($device->getWakeHour() !== null) {
            $tz       = new \DateTimeZone($device->getTimezone());
            $now      = new \DateTimeImmutable('now', $tz);
            $todayWake = $now->setTime($device->getWakeHour(), 0, 0);

            if ($now < $todayWake) {
                return false;
            }

            // Due if no history entry exists since wakeHour today
            $entry = $this->em->createQueryBuilder()
                ->select('h')
                ->from(DeviceImageHistory::class, 'h')
                ->where('h.device = :device')
                ->andWhere('h.servedAt >= :wakeTime')
                ->setParameter('device', $device)
                ->setParameter('wakeTime', $todayWake)
                ->setMaxResults(1)
                ->getQuery()
                ->getOneOrNullResult();

            return $entry === null;
        }

        // Interval-based: due if last history is older than rotationIntervalMinutes
        $last = $this->em->createQueryBuilder()
            ->select('h')
            ->from(DeviceImageHistory::class, 'h')
            ->where('h.device = :device')
            ->setParameter('device', $device)
            ->orderBy('h.servedAt', 'DESC')
            ->setMaxResults(1)
            ->getQuery()
            ->getOneOrNullResult();

        if ($last === null) {
            return true;
        }

        $elapsed = (new \DateTimeImmutable())->getTimestamp() - $last->getServedAt()->getTimestamp();
        return $elapsed >= ($device->getRotationIntervalMinutes() * 60);
    }
}
