<?php

declare(strict_types=1);

namespace Gls\GlsPoland\Configuration\Initializer;

use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain as LegacyDriverChain;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
use Doctrine\Persistence\Mapping\Driver\MappingDriverChain;

/**
 * @internal
 */
final class DoctrineMappingsInitializer implements ConfigurationInitializerInterface
{
    private $entityManager;
    private $module;
    private $doctrineRegistry;

    public function __construct(EntityManagerInterface $entityManager, \Module $module, $doctrineRegistry = null)
    {
        $this->entityManager = $entityManager;
        $this->module = $module;
        $this->doctrineRegistry = $doctrineRegistry;
    }

    public function init(): void
    {
        $namespace = 'Gls\\GlsPoland\\Entity';
        $moduleDriver = new AnnotationDriver(new AnnotationReader(), [$this->module->getLocalPath() . 'src/Entity/']);
        $mappingDriver = $this->entityManager
            ->getConfiguration()
            ->getMetadataDriverImpl();
        $mappingUpdated = false;

        if (!method_exists($mappingDriver, 'addDriver')) {
            $chainClass = class_exists(MappingDriverChain::class)
                ? MappingDriverChain::class
                : LegacyDriverChain::class;
            $chain = new $chainClass();

            if (method_exists($chain, 'setDefaultDriver') && null !== $mappingDriver) {
                $chain->setDefaultDriver($mappingDriver);
            }

            $chain->addDriver($moduleDriver, $namespace);
            $this->entityManager->getConfiguration()->setMetadataDriverImpl($chain);
            $mappingUpdated = true;

            $this->resetManagerIfPossible($mappingUpdated);

            return;
        }

        // Always overwrite mapping for module namespace to avoid stale path after module directory rename/move.
        $mappingDriver->addDriver($moduleDriver, $namespace);
        $mappingUpdated = true;

        $this->resetManagerIfPossible($mappingUpdated);
    }

    private function resetManagerIfPossible(bool $mappingUpdated): void
    {
        if (!$mappingUpdated) {
            return;
        }

        // Avoid resetting manager here: in PrestaShop 1.7 module upload flow, resetManager()
        // may recreate EntityManager without runtime-added module mapping.
        $this->entityManager->clear();
    }
}
