<?php

namespace AutoAdmin\Bundle\Cache\EventListener;

use AutoAdmin\Bundle\Cache\Entity\CacheLog;
use AutoAdmin\Bundle\Cache\Service\CacheService;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Events;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\UnitOfWork;


class ResettingEventListener implements EventSubscriber
{
    private CacheService $service;

    public function __construct(CacheService $service)
    {
        $this->service = $service;
    }

    /**
     * The events the listener is subscribed to.
     *
     * @return array The array of events
     */
    public function getSubscribedEvents(): array
    {
        return [
            Events::prePersist,
            Events::preUpdate,
            Events::preRemove,
            Events::onFlush,
        ];
    }

    public function prePersist(LifecycleEventArgs $event): void
    {
        $this->service->onORMEvent($event->getObject());
    }

    public function preUpdate(LifecycleEventArgs $event): void
    {
        $this->service->onORMEvent($event->getObject());
    }

    public function preRemove(LifecycleEventArgs $event): void
    {
        $this->service->onORMEvent($event->getObject());
    }

    public function onFlush(OnFlushEventArgs $args): void
    {
        if (in_array(PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) {
            return;
        }

        $em = $args->getEntityManager();
        $uow = $em->getUnitOfWork();

        foreach ($uow->getScheduledEntityUpdates() as $entity) {
            $this->handleCacheLog($entity, $em, $uow, 'UPDATE');
        }

        foreach ($uow->getScheduledEntityDeletions() as $entity) {
            $this->handleCacheLog($entity, $em, $uow, 'DELETE');
        }

        foreach ($uow->getScheduledEntityInsertions() as $entity) {
            $this->handleCacheLog($entity, $em, $uow, 'CREATE');
        }
    }

    private function handleCacheLog(object $entity, EntityManagerInterface $em, UnitOfWork $uow, string $type): void
    {
        if (!$this->service->doClearCache($entity)) {
            return;
        }

        if ($entity instanceof CacheLog) {
            return;
        }

        $cacheLog = $this->createCacheLog($entity, $type);
        $em->persist($cacheLog);
        $classMetadata = $em->getClassMetadata(CacheLog::class);
        $uow->computeChangeSet($classMetadata, $cacheLog);
    }

    private function createCacheLog(object $object, string $type): CacheLog
    {
        $cacheLog = new CacheLog();
        $cacheLog->setTriggerType($type);
        $cacheLog->setTriggerClass(get_class($object));
        $cacheLog->setCreatedAt(new DateTime());
        $cacheLog->setUpdatedAt(new DateTime());

        return $cacheLog;
    }
}
