<?php

/*
 * This file is part of the Serenity package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Serenity\MediaBundle\Doctrine\Listener;

use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
use Doctrine\ORM\Event\PostFlushEventArgs;
use Doctrine\ORM\Event\PostLoadEventArgs;
use Doctrine\ORM\Events;
use Serenity\MediaBundle\Contract\AttachmentsInterface;
use Serenity\MediaBundle\Entity\Attachment;

#[AsDoctrineListener(event: Events::postLoad)]
#[AsDoctrineListener(event: Events::postFlush)]
class AttachmentsLoaderListener
{
    /**
     * @var array<string, AttachmentsInterface[]> buffer regroupé par FQCN
     */
    private array $buffer = [];

    public function postLoad(PostLoadEventArgs $args): void
    {
        $entity = $args->getObject();
        if (!$entity instanceof AttachmentsInterface) {
            return;
        }

        // On ajoute l'entité au buffer
        $this->buffer[$entity::class][] = $entity;

        // On injecte par défaut un loader lazy
        $em = $args->getObjectManager();
        $entity->setFilesLoader(function ($parent) use ($em) {
            return $em->getRepository(Attachment::class)
                ->createQueryBuilder('a')
                ->where('a.parentId = :id')
                ->andWhere('a.parentClass = :class')
                ->addOrderBy('a.position', 'ASC')
                ->setParameter('id', $parent->getId())
                ->setParameter('class', $parent::class)
                ->getQuery()
                ->getResult();
        });
    }

    public function postFlush(PostFlushEventArgs $args): void
    {
        if (empty($this->buffer)) {
            return;
        }

        $em = $args->getObjectManager();

        foreach ($this->buffer as $class => $entities) {
            // Si plusieurs entités du même type → on bascule en batch
            if (\count($entities) <= 1) {
                continue; // lazy suffira
            }

            $ids = [];
            foreach ($entities as $entity) {
                if ($entity->getId()) {
                    $ids[] = $entity->getId();
                }
            }

            if (!$ids) {
                continue;
            }

            // Une seule requête par class de parent
            $attachments = $em->getRepository(Attachment::class)
                ->createQueryBuilder('a')
                ->where('a.parentId IN (:ids)')
                ->andWhere('a.parentClass = :class')
                ->addOrderBy('a.position', 'ASC')
                ->setParameter('ids', $ids)
                ->setParameter('class', $class)
                ->getQuery()
                ->getResult();

            // Indexation par parentId
            $byParent = [];
            foreach ($attachments as $attachment) {
                $byParent[(string) $attachment->getParentId()][] = $attachment;
            }

            // Hydrater chaque entité en eager
            foreach ($entities as $entity) {
                $files = $byParent[(string) $entity->getId()] ?? [];
                $entity->setFilesFromPostLoad($files);
            }
        }

        // reset buffer
        $this->buffer = [];
    }
}
