<?php

declare(strict_types=1);

namespace Webapp\Core\Command;

use Doctrine\Common\Annotations\Reader;
use Doctrine\ORM\EntityManagerInterface;
use Gedmo\SoftDeleteable\SoftDeleteableListener;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;

/**
 * Class CleanDeletedFileCommand: Really delete files (request/response) that have been deleted by operators.
 */
class ClearGraphicallyDeletedItemsCommand extends Command
{
    const ARG_DELAY = 'delay';

    const OPT_ACCEPT = 'yes';

    const DEFAULT_DELAY = 24;

    const MAX_LOADING = 2;

    /**
     * @var EntityManagerInterface
     */
    private $entityManager;

    /**
     * @var Reader
     */
    private Reader $annotationReader;

    /**
     * CleanDeletedFileCommand constructor.
     * @param EntityManagerInterface $entityManager
     */
    public function __construct(
        Reader                 $annotationReader,
        EntityManagerInterface $entityManager
    )
    {
        parent::__construct("adonis:graphic:clear");
        $this->entityManager = $entityManager;
        $this->annotationReader = $annotationReader;
    }

    /**
     * @see Command
     */
    protected function configure()
    {
        $this->setDescription(
            'Clear graphically soft deleted objects in database that weren\'t restored.'
        );
        $this->addArgument(
            static::ARG_DELAY,
            InputArgument::OPTIONAL,
            'Delay in days, objects older than this delay (in hour) will be removed');
        $this->addOption(
            static::OPT_ACCEPT,
            ['y'],
            InputOption::VALUE_NONE,
            'Accept all changes without asking');
    }

    /**
     * @param InputInterface $input
     * @param OutputInterface $output
     * @return int
     * @see Command
     */
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $delay = static::DEFAULT_DELAY;
        if ($input->getArgument(static::ARG_DELAY) !== null) {

            // Delay in hour from execution date.
            $delay = $input->getArgument(static::ARG_DELAY);
        }
        $deletionDateLimit = date_create();
        $deletionDateLimit->modify("-${delay} hour");
        $output->writeln(
            'Delete all objets that have been deleted before date: '
            . $deletionDateLimit->format('Y-m-d H:i')
        );
        if ($this->entityManager->getFilters()->isEnabled('graphically_deletable')) {
            $this->entityManager->getFilters()->disable('graphically_deletable');
        }
        if($this->entityManager->getFilters()->isEnabled('soft_deleteable')){
            $this->entityManager->getFilters()->disable('soft_deleteable');
        }
        $objectFound = [];
        foreach ($this->entityManager->getMetadataFactory()->getAllMetadata() as $classMetadata) {
            $annotation = $this->annotationReader->getClassAnnotation($classMetadata->getReflectionClass(), 'Webapp\\Core\\Annotation\\GraphicallyDeletable');
            if (null !== $annotation && isset($annotation->graphicallyDeletableField)) {
                $qb = $this->entityManager->createQueryBuilder();
                $items = $qb
                    ->select('i')
                    ->from($classMetadata->getName(), 'i')
                    ->where($qb->expr()->lt("i.$annotation->graphicallyDeletableField", ":date"))
                    ->setParameter('date', $deletionDateLimit)
                    ->getQuery()->execute();
                foreach ($items as $item) {
                    $objectFound[] = $item;
                }
            }
        }
        $helper = $this->getHelper('question');
        $count = count($objectFound);
        $question = new ConfirmationQuestion("Delete $count items ?", false);

        if ($input->getOption(static::OPT_ACCEPT) || $helper->ask($input, $output, $question)) {
            $originalEventListeners = [];

            foreach ($this->entityManager->getEventManager()->getListeners() as $eventName => $listeners) {
                foreach ($listeners as $listener) {
                    if ($listener instanceof SoftDeleteableListener) {
                        $originalEventListeners[$eventName] = $listener;
                        $this->entityManager->getEventManager()->removeEventListener($eventName, $listener);
                    }
                }
            }

            foreach ($objectFound as $item) {
                $this->entityManager->remove($item);
            }
            $this->entityManager->flush();

            foreach ($originalEventListeners as $eventName => $listener) {
                $this->entityManager->getEventManager()->addEventListener($eventName, $listener);
            }

            $output->writeln("Deleted $count items");
        }
        return 0;
    }


}
