<?php

declare(strict_types=1);

namespace Webapp\Core\Command;

use Doctrine\ORM\EntityManagerInterface;
use Shared\Application\Entity\File;
use Shared\TransferSync\Entity\StatusDataEntry;
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;
use Vich\UploaderBundle\Handler\UploadHandler;
use Webapp\Core\Entity\Parameters;
use Webapp\FileManagement\Entity\ParsingJob;
use Webapp\FileManagement\Entity\RequestFile;
use Webapp\FileManagement\Entity\ResponseFile;

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

    const OPT_ACCEPT = 'yes';

    const FILE_CLASS_NAMES = [
        RequestFile::class,
        ResponseFile::class,
        File::class,
        ParsingJob::class,
    ];

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

    /**
     * @var UploadHandler
     */
    private UploadHandler $handler;

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

    /**
     * @see Command
     */
    protected function configure()
    {
        $this->setDescription(
            'Clear files that are soft deleted'
        );
        $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 = $this->entityManager->getRepository(Parameters::class)->find(1)->getDaysBeforeFileDelete();
        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} day");
        $output->writeln(
            'Delete all files that have been deleted before date: '
            . $deletionDateLimit->format('Y-m-d H:i')
        );
        if ($this->entityManager->getFilters()->isEnabled('soft_deleteable')) {
            $this->entityManager->getFilters()->disable('soft_deleteable');
        }
        $objectFound = [];
        foreach (self::FILE_CLASS_NAMES as $className) {
            $qb = $this->entityManager->createQueryBuilder();
            $items = $qb
                ->select('i')
                ->from($className, 'i')
                ->where($qb->expr()->lt("i.deletedAt", ":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)) {

            foreach ($objectFound as $item) {
                $this->handler->remove($item, "file");
                $this->entityManager->remove($item);
                if ($item instanceof ResponseFile) {
                    $status = $this->entityManager->getRepository(StatusDataEntry::class)->findOneBy(['response' => $item->getProject()]);
                    if($status !== null){
                        $status->setSyncable(false);
                    }
                }
                if ($item instanceof RequestFile) {
                    $status = $this->entityManager->getRepository(StatusDataEntry::class)->findOneBy(['request' => $item->getProject()]);
                    if($status !== null){
                        $status->setSyncable(false);
                    }
                }
            }
            $this->entityManager->flush();

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


}
