<?php

namespace App\Listener;

use App\Entity\AccountAdherent;
use App\Entity\AccountComptoir;
use App\Entity\AccountGroupe;
use App\Entity\AccountPrestataire;
use App\Entity\AccountSiege;
use App\Entity\Adherent;
use App\Entity\Comptoir;
use App\Entity\Flux;
use App\Entity\Groupe;
use App\Entity\Prestataire;
use App\Entity\Siege;
use App\Entity\User;
use App\Enum\CurrencyEnum;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Events;
use Symfony\Component\Security\Core\Security;

class FluxListener implements EventSubscriber
{
    private $em;
    private $security;

    public function __construct(EntityManagerInterface $em, Security $security)
    {
        $this->em = $em;
        $this->security = $security;
    }

    public function getSubscribedEvents()
    {
        return [Events::onFlush];
    }

    private function persistAndCompute($em, $entity)
    {
        $em->persist($entity);
        $class = $em->getClassMetadata(get_class($entity));
        $em->getUnitOfWork()->computeChangeSet($class, $entity);
    }

    /**
     * @deprecated
     */
    public function onFlush(OnFlushEventArgs $args)
    {
        $em = $args->getEntityManager();
        $uow = $em->getUnitOfWork();

        $inserted = $uow->getScheduledEntityInsertions();

        /*
         * @deprecated OLD operate() system !
         */
        // $em->getConnection()->beginTransaction(); // suspend auto-commit
        // try {
        //     foreach ($inserted as $entity) {

        //         // if ($entity instanceof Flux) {
        //         //     $topersists = $entity->operate($em);
        //         //     foreach ($topersists as $topersist) {
        //         //         $class = $em->getClassMetadata(get_class($topersist));
        //         //         $em->persist($topersist);
        //         //         $em->getUnitOfWork()->computeChangeSet($class, $topersist);
        //         //     }
        //         //     // @TODO : do something (log, save somewhere else...) on flux persist
        //         //     //      => @tag sur un service ?
        //         // }
        //     }
        //     $em->getConnection()->commit();
        // } catch (\Exception $e) {
        //     $em->getConnection()->rollBack();
        //     // @TODO : better exception management
        //     throw $e;
        // }

        $em->getConnection()->beginTransaction();
        $updated = $uow->getScheduledEntityUpdates();
        try {
            foreach ($updated as $entity) {
                // Create account(s) if needed !
                if ($entity instanceof Adherent) {
                    $account = $this->em->getRepository(AccountAdherent::class)->findOneBy(['adherent' => $entity, 'currency' => CurrencyEnum::CURRENCY_EMLC]);
                    if (null == $account) {
                        $account = new AccountAdherent();
                        $account
                            ->setCurrency(CurrencyEnum::CURRENCY_EMLC)
                        ;
                        $entity->addAccount($account);
                        $this->persistAndCompute($em, $account);
                        $this->persistAndCompute($em, $entity);
                    }
                } elseif ($entity instanceof Prestataire) {
                    $account = $this->em->getRepository(AccountPrestataire::class)->findOneBy(['prestataire' => $entity, 'currency' => CurrencyEnum::CURRENCY_EMLC]);
                    if (null == $account) {
                        $account = new AccountPrestataire();
                        $account
                            ->setCurrency(CurrencyEnum::CURRENCY_EMLC)
                        ;
                        $entity->addAccount($account);
                        $this->persistAndCompute($em, $account);
                        if ($entity->isMlc()) {
                            $accountEuro = $this->em->getRepository(AccountPrestataire::class)->findOneBy(['prestataire' => $entity, 'currency' => CurrencyEnum::CURRENCY_EURO]);
                            if (null == $accountEuro) {
                                // Ajout du compte de fonctionnement euro pour le prestataire MLC
                                $accountEuro = new AccountPrestataire();
                                $accountEuro
                                    ->setCurrency(CurrencyEnum::CURRENCY_EURO)
                                ;
                                $entity->addAccount($accountEuro);
                                $this->persistAndCompute($em, $accountEuro);
                            }
                        }
                        $this->persistAndCompute($em, $entity);
                    }
                } elseif ($entity instanceof Groupe) {
                    $account = $this->em->getRepository(AccountGroupe::class)->findOneBy(['groupe' => $entity, 'currency' => CurrencyEnum::CURRENCY_MLC]);
                    if (null == $account) {
                        $account = new AccountGroupe();
                        $account
                            ->setCurrency(CurrencyEnum::CURRENCY_MLC)
                        ;
                        $entity->addAccount($account);
                        $this->persistAndCompute($em, $account);
                        $this->persistAndCompute($em, $entity);
                    }
                } elseif ($entity instanceof Comptoir) {
                    $account = $this->em->getRepository(AccountComptoir::class)->findOneBy(['comptoir' => $entity, 'currency' => CurrencyEnum::CURRENCY_MLC]);
                    if (null == $account) {
                        $account = new AccountComptoir();
                        $account
                            ->setCurrency(CurrencyEnum::CURRENCY_MLC)
                        ;
                        $entity->addAccount($account);
                        $this->persistAndCompute($em, $account);
                        $this->persistAndCompute($em, $entity);
                    }
                } elseif ($entity instanceof Siege) {
                    $account = $this->em->getRepository(AccountSiege::class)->findOneBy(['siege' => $entity, 'currency' => CurrencyEnum::CURRENCY_MLC]);
                    if (null == $account) {
                        $account = new AccountSiege();
                        $account
                            ->setCurrency(CurrencyEnum::CURRENCY_MLC)
                        ;
                        $entity->addAccount($account);
                        $this->persistAndCompute($em, $account);
                    }
                    $account = $this->em->getRepository(AccountSiege::class)->findOneBy(['siege' => $entity, 'currency' => CurrencyEnum::CURRENCY_EMLC]);
                    if (null == $account) {
                        $account = new AccountSiege();
                        $account
                            ->setCurrency(CurrencyEnum::CURRENCY_EMLC)
                        ;
                        $entity->addAccount($account);
                        $this->persistAndCompute($em, $account);
                    }
                    $account = $this->em->getRepository(AccountSiege::class)->findOneBy(['siege' => $entity, 'currency' => CurrencyEnum::CURRENCY_MLC_NANTIE]);
                    if (null == $account) {
                        $account = new AccountSiege();
                        $account
                            ->setCurrency(CurrencyEnum::CURRENCY_MLC_NANTIE)
                        ;
                        $entity->addAccount($account);
                        $this->persistAndCompute($em, $account);
                    }
                    $this->persistAndCompute($em, $entity);
                }

                //         if ($entity instanceof Flux) {
        //             $changeset = $uow->getEntityChangeSet($entity);
        //             // if ($entity->getParentType() == Flux::TYPE_DEMANDE_ACHAT && isset($changeset['reconverti'])) {
        //             //     $operateur = null;
        //             //     if ($changeset['reconverti'][0] === true) {
        //             //         throw new \Exception("Opération impossible ! Vous ne pouvez pas invalider un achat de monnaie !");
        //             //     }
        //             //     // Si l'opérateur a changé
        //             //     if (isset($changeset['operateur']) && $changeset['operateur'][1] != null && $changeset['operateur'][1] instanceof User) {
        //             //         $operateur = $changeset['operateur'][1];
        //             //         if (!$operateur->hasRole('ROLE_VALIDE_ACHAT')) {
        //             //             $operateur = null;
        //             //         }
        //             //     }
        //             //     $em->refresh($entity->getOperateur());
        //             //     if ($operateur == null && $entity->getOperateur() != null && $entity->getOperateur() instanceof User && $entity->getOperateur()->hasRole('ROLE_VALIDE_ACHAT')) {
        //             //         $operateur = $entity->getOperateur();
        //             //     }
        //             //     if ($operateur != null) {
        //             //         // Validate and Operate the transaction = buy e-MLC
        //             //         // Increment siege's ecompte nantie of e-MLC
        //             //         $entity->getExpediteur()->addEcompteNantie($entity->getMontant());
        //             //         // Increment account of adherent/prestataire
        //             //         $entity->getDestinataire()->addEcompte($entity->getMontant());
        //             //         $class = $em->getClassMetadata(get_class($entity->getExpediteur()));
        //             //         $em->persist($entity->getExpediteur());
        //             //         $uow->computeChangeSet($class, $entity->getExpediteur());
        //             //         $class = $em->getClassMetadata(get_class($entity->getDestinataire()));
        //             //         $em->persist($entity->getDestinataire());
        //             //         $uow->computeChangeSet($class, $entity->getDestinataire());
        //             //     } else {
        //             //         throw new \Exception("Opération impossible ! Vous n'avez pas les droits pour valider cet achat de monnaie !");
        //             //     }
        //             // }

        //             // Update hash with new value from flux updated
        //             // @TODO : re calculate hash only if validate and needed ! => check permissions / actions and data updated
        //             $entity->updateHash();
        //             $class = $em->getClassMetadata(get_class($entity));
        //             $em->persist($entity);
        //         }
            }
            $em->getConnection()->commit();
        } catch (\Exception $e) {
            $em->getConnection()->rollBack();
            // @TODO : better exception management
            throw $e;
        }
    }
}