<?php

declare(strict_types=1);

namespace App\Shared\Infrastructure\Doctrine;

use App\Shared\Application\CurrentUserProviderInterface;
use App\Shared\Domain\Contract\BlamableInterface;
use App\Shared\Domain\Contract\TimestampableInterface;
use DateTimeImmutable;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
use Doctrine\ORM\Event\PrePersistEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Doctrine\ORM\Events;

#[AsDoctrineListener(event: Events::prePersist)]
#[AsDoctrineListener(event: Events::preUpdate)]
final readonly class TimestampableBlamableSubscriber
{
    public function __construct(
        private CurrentUserProviderInterface $currentUserProvider,
    ) {}

    public function prePersist(PrePersistEventArgs $args): void
    {
        $this->applyOnCreate($args->getObject());
    }

    public function preUpdate(PreUpdateEventArgs $args): void
    {
        $this->applyOnUpdate($args->getObject());
    }

    public function applyOnCreate(object $entity): void
    {
        $now = new DateTimeImmutable();

        if ($entity instanceof TimestampableInterface) {
            if (null === $entity->getCreatedAt()) {
                $entity->setCreatedAt($now);
            }
            $entity->setUpdatedAt($now);
        }

        if ($entity instanceof BlamableInterface) {
            $user = $this->currentUserProvider->getCurrentUser();
            if (null === $entity->getCreatedBy()) {
                $entity->setCreatedBy($user);
            }
            $entity->setUpdatedBy($user);
        }
    }

    public function applyOnUpdate(object $entity): void
    {
        if ($entity instanceof TimestampableInterface) {
            $entity->setUpdatedAt(new DateTimeImmutable());
        }

        if ($entity instanceof BlamableInterface) {
            $entity->setUpdatedBy($this->currentUserProvider->getCurrentUser());
        }
    }
}
