<?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\CoreBundle\Shared\Doctrine\EventListener;

use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Schema\PostgreSQLSchemaManager;
use Doctrine\DBAL\Schema\SchemaException;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
use Doctrine\ORM\Tools\ToolEvents;

/**
 * UPDATE 12/01/26 : Plus nécessaire avec dbal 4
 * Listener Doctrine : FixPostgresSQLDefaultSchemaListener.
 *
 * ## Objectif
 * Ce listener corrige un comportement de Doctrine lors de la génération
 * du schéma sur PostgreSQL :
 * Doctrine ne crée pas toujours les *namespaces* (schémas SQL) existants
 * dans la base, ce qui peut provoquer des erreurs ou des incohérences
 * lorsqu’on utilise plusieurs schémas (autres que `public`).
 *
 * En interceptant l’événement `postGenerateSchema`, ce listener :
 *  - Récupère la liste des schémas connus par le gestionnaire PostgreSQL ;
 *  - Vérifie leur existence dans l’objet `Schema` généré par Doctrine ;
 *  - Crée les namespaces manquants afin d’éviter les erreurs
 *    lors de la génération ou de la synchronisation du schéma.
 *
 * ## Fonctionnement
 * 1. Doctrine déclenche l’événement `postGenerateSchema`
 *    après avoir généré le schéma des entités.
 * 2. Le listener intercepte cet événement.
 * 3. Si le `SchemaManager` est bien un `PostgreSQLSchemaManager`,
 *    il synchronise les namespaces du schéma Doctrine avec ceux du serveur PostgreSQL.
 *
 * ## Exemple d’utilisation
 * Ce listener est automatiquement enregistré via l’attribut
 * `#[AsDoctrineListener(event: ToolEvents::postGenerateSchema)]`.
 *
 * Aucune configuration supplémentaire n’est nécessaire.
 *
 * Il agit en interne lors de l’exécution de :
 * ```bash
 * php bin/console doctrine:schema:create
 * php bin/console doctrine:schema:update --force
 * ```
 *
 * ## Notes techniques
 * - Compatible uniquement avec PostgreSQL.
 * - Sans effet sur MySQL, SQLite ou autres moteurs.
 * - Protégé contre les exceptions liées à la gestion des schémas inexistants.
 *
 * @see PostgreSQLSchemaManager
 * @see GenerateSchemaEventArgs
 * @see ToolEvents::postGenerateSchema
 *
 * @throws SchemaException si une incohérence de schéma est détectée
 * @throws Exception       en cas d’erreur DBAL
 */
final class FixPostgresSQLDefaultSchemaListener
{
    /**
     * @throws SchemaException
     * @throws Exception
     */
    public function __invoke(GenerateSchemaEventArgs $args): void
    {
        $schemaManager = $args
          ->getEntityManager()
          ->getConnection()
          ->createSchemaManager();

        if (!$schemaManager instanceof PostgreSQLSchemaManager) {
            return;
        }

        $schema = $args->getSchema();

        foreach ($schemaManager->listSchemaNames() as $namespace) {
            if (!$schema->hasNamespace($namespace)) {
                $schema->createNamespace($namespace);
            }
        }
    }
}
