<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\MainBundle\Notification\Counter;

use Chill\MainBundle\Entity\Notification;
use Chill\MainBundle\Entity\NotificationComment;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\NotificationRepository;
use Chill\MainBundle\Templating\UI\NotificationCounterInterface;
use Doctrine\ORM\Event\PostPersistEventArgs;
use Doctrine\ORM\Event\PostUpdateEventArgs;
use Doctrine\ORM\Event\PreFlushEventArgs;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Security\Core\User\UserInterface;

final readonly class NotificationByUserCounter implements NotificationCounterInterface
{
    public function __construct(private CacheItemPoolInterface $cacheItemPool, private NotificationRepository $notificationRepository) {}

    public function addNotification(UserInterface $u): int
    {
        if (!$u instanceof User) {
            return 0;
        }

        return $this->countUnreadByUser($u);
    }

    public function countUnreadByUser(User $user): int
    {
        $key = self::generateCacheKeyUnreadNotificationByUser($user);

        $item = $this->cacheItemPool->getItem($key);

        if ($item->isHit()) {
            return $item->get();
        }

        $unreads = $this->notificationRepository->countUnreadByUser($user);

        $item
            ->set($unreads)
            // keep in cache for 15 minutes
            ->expiresAfter(60 * 15);
        $this->cacheItemPool->save($item);

        return $unreads;
    }

    public static function generateCacheKeyUnreadNotificationByUser(User $user): string
    {
        return 'chill_main_notif_unread_by_'.$user->getId();
    }

    public function onPersistNotificationComment(NotificationComment $notificationComment, PostPersistEventArgs $eventArgs): void
    {
        $this->resetCacheForNotification($notificationComment->getNotification());
    }

    public function onEditNotificationComment(NotificationComment $notificationComment, PostUpdateEventArgs $eventArgs): void
    {
        $this->resetCacheForNotification($notificationComment->getNotification());
    }

    public function onPreFlushNotification(Notification $notification, PreFlushEventArgs $eventArgs): void
    {
        $this->resetCacheForNotification($notification);
    }

    private function resetCacheForNotification(Notification $notification): void
    {
        $keys = [];

        if (null !== $notification->getSender()) {
            $keys[] = self::generateCacheKeyUnreadNotificationByUser($notification->getSender());
        }

        foreach ($notification->getAddressees() as $addressee) {
            $keys[] = self::generateCacheKeyUnreadNotificationByUser($addressee);
        }

        $this->cacheItemPool->deleteItems($keys);
    }
}
