<?php

declare(strict_types=1);

namespace App\Command;

use App\Entity\Comptoir;
use App\Entity\Groupe;
use App\Entity\OperationAdherent;
use App\Entity\OperationComptoir;
use App\Entity\OperationGroupe;
use App\Entity\OperationPrestataire;
use App\Entity\OperationSiege;
use App\Entity\Prestataire;
use App\Entity\Siege;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

/**
 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
 */
class CheckAccountsBalanceCommand extends Command
{
    protected static $defaultName = 'kohinos:accounts:check';

    protected $em;
    protected $io;

    public function __construct(
        EntityManagerInterface $em
    ) {
        $this->em = $em;
        parent::__construct();
    }

    protected function configure()
    {
        $this
            ->setDescription("Check account's balance for all entities (siege, groupe, comptoir, adherent, prestataire)")
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $this->io = new SymfonyStyle($input, $output);
        $this->em->getConnection()->getConfiguration()->setSQLLogger(null);

        $this->io->title('Start checking accounts');
        $this->checkAllAccount();
        $this->io->success('All accounts have been checked !');

        $this->io->title('Start checking operations');
        $this->checkAllOperation();
        $this->io->success('All operations have been checked !');

        $memoryUsage = memory_get_usage(true) / 1024 / 1024;
        $this->io->text("Batch finished with memory: ${memoryUsage}M");

        return 0;
    }

    private function checkAllOperation()
    {
        $operationsAdherent = $this->em->getRepository(OperationAdherent::class)->findAll();
        $countOperationOk = 0;
        foreach ($operationsAdherent as $op) {
            if (password_verify($op->getAllInfosUncrypted(), $op->getHash())) {
                ++$countOperationOk;
            } else {
                $this->io->error('Operation ' . $op->getId() . " de l'adherent invalide ! ");
            }
        }
        unset($operationsAdherent);
        gc_collect_cycles();
        $this->io->success('Nb d\'operations ADHERENT OK : ' . $countOperationOk . ' !');
        $countOperationOk = 0;
        $this->em->clear();
        $operationsPrestataire = $this->em->getRepository(OperationPrestataire::class)->findAll();
        foreach ($operationsPrestataire as $op) {
            if (password_verify($op->getAllInfosUncrypted(), $op->getHash())) {
                ++$countOperationOk;
            } else {
                $this->io->error('Operation ' . $op->getId() . ' du prestataire invalide ! ');
            }
        }
        unset($operationsPrestataire);
        gc_collect_cycles();
        $this->io->success('Nb d\'operations PRESTATAIRE OK : ' . $countOperationOk . ' !');
        $countOperationOk = 0;
        $this->em->clear();
        $operationsComptoir = $this->em->getRepository(OperationComptoir::class)->findAll();
        foreach ($operationsComptoir as $op) {
            if (password_verify($op->getAllInfosUncrypted(), $op->getHash())) {
                ++$countOperationOk;
            } else {
                $this->io->error('Operation ' . $op->getId() . ' du comptoir invalide ! ');
            }
        }
        unset($operationsComptoir);
        gc_collect_cycles();
        $this->io->success('Nb d\'operations COMPTOIR OK : ' . $countOperationOk . ' !');
        $countOperationOk = 0;
        $this->em->clear();
        $operationsGroupe = $this->em->getRepository(OperationGroupe::class)->findAll();
        foreach ($operationsGroupe as $op) {
            if (password_verify($op->getAllInfosUncrypted(), $op->getHash())) {
                ++$countOperationOk;
            } else {
                $this->io->error('Operation ' . $op->getId() . ' du groupe invalide ! ');
            }
        }
        $this->io->success('Nb d\'operations GROUPE OK : ' . $countOperationOk . ' !');
        $countOperationOk = 0;
        unset($operationsGroupe);
        gc_collect_cycles();
        $this->em->clear();
        $operationsSiege = $this->em->getRepository(OperationSiege::class)->findAll();
        foreach ($operationsSiege as $op) {
            if (password_verify($op->getAllInfosUncrypted(), $op->getHash())) {
                ++$countOperationOk;
            } else {
                $this->io->error('Operation ' . $op->getId() . ' du siege invalide ! ');
            }
        }
        unset($operationsSiege);
        gc_collect_cycles();
        $this->io->success('Nb d\'operations SIEGE OK : ' . $countOperationOk . ' !');
    }

    private function checkAllAccount()
    {
        $users = $this->em->getRepository(User::class)->findAll();
        $countAccountOk = 0;
        foreach ($users as $entity) {
            // Create all accounts link to this entity if not exist !
            if (!empty($entity->getAdherent())) {
                if (count($entity->getAdherent()->getAccounts()) > 0) {
                    foreach ($entity->getAdherent()->getAccounts() as $account) {
                        if (password_verify($account->getAllInfosUncrypted(), $account->getHash())) {
                            ++$countAccountOk;
                        } else {
                            $this->io->error('Compte ' . $account->getCurrency() . " de l'adherent : " . $entity->getAdherent() . ' (id: ' . $entity->getAdherent()->getId() . ') invalide ! ');
                        }
                    }
                }
            }
        }
        unset($users);
        gc_collect_cycles();
        $this->em->clear();
        $this->io->success('Nb de compte adherent OK : ' . $countAccountOk . ' !');
        $countAccountOk = 0;
        $prestas = $this->em->getRepository(Prestataire::class)->findAll();
        foreach ($prestas as $presta) {
            if (count($presta->getAccounts()) > 0) {
                foreach ($presta->getAccounts() as $account) {
                    if (password_verify($account->getAllInfosUncrypted(), $account->getHash())) {
                        ++$countAccountOk;
                    } else {
                        $this->io->error('Compte ' . $account->getCurrency() . ' du presta : ' . $presta . ' (id: ' . $presta->getId() . ') invalide ! ');
                    }
                }
            }
        }
        unset($prestas);
        gc_collect_cycles();
        $this->em->clear();
        $this->io->success('Nb de compte prestataire OK : ' . $countAccountOk . ' !');
        $countAccountCreated = 0;
        $this->em->flush();
        $comptoirs = $this->em->getRepository(Comptoir::class)->findAll();
        foreach ($comptoirs as $comptoir) {
            if (count($comptoir->getAccounts()) > 0) {
                foreach ($comptoir->getAccounts() as $account) {
                    if (password_verify($account->getAllInfosUncrypted(), $account->getHash())) {
                        ++$countAccountOk;
                    } else {
                        $this->io->error('Compte ' . $account->getCurrency() . ' du comptoir : ' . $comptoir . ' (id: ' . $comptoir->getId() . ') invalide ! ');
                    }
                }
            }
        }
        unset($comptoirs);
        gc_collect_cycles();
        $this->em->clear();
        $this->io->success('Nb de compte comptoir OK : ' . $countAccountOk . ' !');
        $countAccountCreated = 0;
        $this->em->flush();
        $groupes = $this->em->getRepository(Groupe::class)->findAll();
        foreach ($groupes as $groupe) {
            if (count($groupe->getAccounts()) <= 0) {
                foreach ($groupe->getAccounts() as $account) {
                    if (password_verify($account->getAllInfosUncrypted(), $account->getHash())) {
                        ++$countAccountOk;
                    } else {
                        $this->io->error('Compte ' . $account->getCurrency() . ' du groupe : ' . $groupe . ' (id: ' . $groupe->getId() . ') invalide ! ');
                    }
                }
            }
        }
        unset($groupes);
        gc_collect_cycles();
        $this->em->clear();
        $this->io->success('Nb de compte groupe OK : ' . $countAccountOk . ' !');
        $countAccountCreated = 0;
        $this->em->flush();
        $siege = $this->em->getRepository(Siege::class)->findOneById(1);
        if (count($siege->getAccounts()) <= 0) {
            foreach ($siege->getAccounts() as $account) {
                if (password_verify($account->getAllInfosUncrypted(), $account->getHash())) {
                    ++$countAccountOk;
                } else {
                    $this->io->error('Compte ' . $account->getCurrency() . ' du siege : ' . $groupe . ' invalide ! ');
                }
            }
        }
        unset($siege);
        gc_collect_cycles();
        $this->em->clear();
        $this->io->success('Nb de compte siege OK : ' . $countAccountOk . ' !');
    }
}
