<?php

namespace Webapp\FileManagement\Service;

use Doctrine\ORM\EntityManagerInterface;
use Mobile\Project\Entity\DataEntryProject;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Shared\Enumeration\DoctrineFilterEnum;
use Shared\FileManagement\Entity\UserLinkedJob;
use Shared\TransferSync\Entity\StatusDataEntry;
use Shared\TransferSync\Worker\IndividualStructureCheckHelper;
use Symfony\Component\Process\Exception\LogicException;
use Vich\UploaderBundle\Storage\StorageInterface;
use Webapp\FileManagement\Dto\Mobile\XmlWithFiles;
use Webapp\FileManagement\Entity\ResponseFile;
use Webapp\FileManagement\Exception\WritingException;

class MobileWriterService extends AbstractWriterService implements LoggerAwareInterface
{
    use LoggerAwareTrait;

    private const SITE_NAMESPACE = 'adonis.modeleMetier.site';

    private IndividualStructureCheckHelper $checkWorker;

    private string $desktopVersion;
    private MobileXmlWriterService $mobileXmlWriterService;

    public function __construct(EntityManagerInterface $entityManager,
        DirectoryNamer $directoryNameManager,
        StorageInterface $storage,
        IndividualStructureCheckHelper $checkWorker,
        MobileXmlWriterService $mobileXmlWriterService,
        string $tmpDir,
        string $desktopVersion
    ) {
        parent::__construct($entityManager, $directoryNameManager, $storage, $tmpDir);
        $this->desktopVersion = $desktopVersion;
        $this->checkWorker = $checkWorker;
        $this->mobileXmlWriterService = $mobileXmlWriterService;
    }

    /**
     * Main function of the writer.
     *
     * @throws \ReflectionException
     * @throws WritingException|\DOMException
     */
    public function createFile(int $responseFileId, ?int $statusProjectId = null)
    {
        // Disable SoftDeleteableFilter to allow multiple returns.
        $this->entityManager->getFilters()->disable(DoctrineFilterEnum::SOFT_DELETEABLE);

        $responseFile = $this->entityManager->getRepository(ResponseFile::class)->find($responseFileId);
        $statusRepo = $this->entityManager->getRepository(StatusDataEntry::class);
        /** @var StatusDataEntry|null $statusDataEntry */
        $statusDataEntry = null === $statusProjectId ? $statusRepo->findOneByResponseProject($responseFile->getProject()) : $statusRepo->find($statusProjectId);
        $this->entityManager->getFilters()->enable(DoctrineFilterEnum::SOFT_DELETEABLE);

        if (null === $statusDataEntry) {
            if ($this->logger) {
                $this->logger->warning('StatusDataEntry does not exist.');
            }

            return;
        }

        $projectResult = $statusDataEntry->getResponse();
        if (null === $projectResult) {
            throw new LogicException('Response does not exist');
        }

        $responseFile->setStatus(UserLinkedJob::STATUS_RUNNING);
        $this->entityManager->flush();

        $projectName = $projectResult->getName();
        $fileName = sprintf('Transfert-%s-%s.zip',
            iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $projectName),
            $responseFile->getUploadDate()->format(self::dateFormat));
        $responseFile->setFilePath($fileName);

        $xmlWithFiles = $this->mobileXmlWriterService->generateDataEntry($projectResult);

        $this->createZipFile($xmlWithFiles, $responseFile);

        if (!is_null($statusDataEntry->getWebappProject())) {
            $this->checkWorker->checkDataEntry($statusDataEntry);
        }

        $statusDataEntry->setSyncable(false);

        $statusDataEntry->setStatus(StatusDataEntry::STATUS_DONE);
        $responseFile->setStatus(UserLinkedJob::STATUS_SUCCESS);
        $this->entityManager->flush();
    }

    /**
     * Create the zip file.
     *
     * @throws WritingException
     */
    private function createZipFile(XmlWithFiles $xmlWithFiles, ResponseFile $responseFile): void
    {
        $tmpDir = $this->getTmpDir($responseFile);
        $tmpFilePath = $tmpDir.'/transfert.xml';
        $filePath = $tmpDir.'/'.$responseFile->getFilePath();

        $zipFile = new \ZipArchive();
        if (true === $zipFile->open($filePath, \ZipArchive::CREATE)) {
            // Add the annotation pictures to the zip file
            foreach ($xmlWithFiles->getFiles() as $key => $annotationFile) {
                $content = file_get_contents($annotationFile);
                file_put_contents($tmpDir.'/'.$key, $content);
                $zipFile->addFile($tmpDir.'/'.$key, $key);
            }
            file_put_contents($tmpFilePath, $xmlWithFiles->getXml());
            $zipFile->addFile($tmpFilePath, 'transfert.xml');
            $zipFile->addFromString('umpc', '');
            $zipFile->close();
            $this->copyFileFromTmpDir($responseFile);
        } else {
            throw new WritingException('Unable to create zip file');
        }
        $this->cleanTmpDir($responseFile);
    }

    public function constructProjectZipFile(DataEntryProject $project, string $fileName): void
    {
        $xmlWithFiles = $this->mobileXmlWriterService->generateDataEntryProject($project);

        $zipFile = new \ZipArchive();
        if (true === $zipFile->open($fileName, \ZipArchive::CREATE)) {
            foreach ($xmlWithFiles->getFiles() as $key => $markFile) {
                $content = file_get_contents($markFile);
                $zipFile->addFromString($key, $content);
            }
            $zipFile->addFromString($project->getName().'.xml', $xmlWithFiles->getXml());
            $zipFile->close();
        }
    }
}
