<?php

namespace App\Command;

use App\Repository\AttestationRepository;
use Doctrine\ORM\EntityManagerInterface;
use Docuseal\Api;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Filesystem\Filesystem;

#[AsCommand(
    name: 'app:attestations:clean',
    description: 'Supprime les attestations de plus de 7 jours (fichiers, BDD et DocuSeal)',
)]
class CleanAttestationsCommand extends Command
{
    private Api $docuSealApi;

    public function __construct(
        private EntityManagerInterface $em,
        private AttestationRepository $repository,
        private Filesystem $filesystem,
        #[Autowire('%kernel.project_dir%')] private string $projectDir,
        #[Autowire(env: 'DOCUSEAL_URL')] string $docuSealUrl,
        #[Autowire(env: 'DOCUSEAL_API')] string $docuSealApiKey,
    ) {
        parent::__construct();
        $this->docuSealApi = new Api($docuSealApiKey, rtrim($docuSealUrl, '/').'/api');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $expireDate = new \DateTimeImmutable('-7 days');

        $attestations = $this->repository->createQueryBuilder('a')
            ->where('a.createdAt < :expireDate')
            ->setParameter('expireDate', $expireDate)
            ->getQuery()
            ->getResult();

        if (0 === \count($attestations)) {
            $io->success('Aucune attestation a supprimer.');

            return Command::SUCCESS;
        }

        $deleted = 0;

        foreach ($attestations as $attestation) {
            // Supprimer les fichiers PDF locaux
            $this->deleteFile($attestation->getPdfFileUnsigned());
            $this->deleteFile($attestation->getPdfFileSigned());
            $this->deleteFile($attestation->getPdfFileCertificate());

            // Supprimer sur DocuSeal
            $submitterId = $attestation->getSubmitterId();
            if (null !== $submitterId) {
                $this->deleteFromDocuSeal($submitterId, $io);
            }

            // Supprimer en BDD
            $this->em->remove($attestation);
            ++$deleted;
        }

        $this->em->flush();

        // Nettoyer les fichiers orphelins dans var/rgpd
        $this->cleanOrphanFiles($expireDate, $io);

        $io->success(sprintf('%d attestation(s) supprimee(s).', $deleted));

        return Command::SUCCESS;
    }

    private function deleteFile(?string $path): void
    {
        if (null !== $path && $this->filesystem->exists($path)) {
            $this->filesystem->remove($path);
        }
    }

    private function deleteFromDocuSeal(int $submitterId, SymfonyStyle $io): void
    {
        try {
            $submitter = $this->docuSealApi->getSubmitter($submitterId);
            $submissionId = $submitter['submission_id'] ?? null;

            if (null !== $submissionId) {
                $this->docuSealApi->permanentlyDeleteSubmission($submissionId);
            }
        } catch (\Throwable $e) {
            $io->warning('DocuSeal: impossible de supprimer le submitter '.$submitterId.': '.$e->getMessage());
        }
    }

    private function cleanOrphanFiles(\DateTimeImmutable $expireDate, SymfonyStyle $io): void
    {
        $dirs = [
            $this->projectDir.'/var/rgpd',
            $this->projectDir.'/var/rgpd/signed',
        ];

        $orphans = 0;

        foreach ($dirs as $dir) {
            if (!$this->filesystem->exists($dir)) {
                continue;
            }

            foreach (new \DirectoryIterator($dir) as $file) {
                if ($file->isDot() || $file->isDir()) {
                    continue;
                }

                if ($file->getMTime() < $expireDate->getTimestamp()) {
                    $this->filesystem->remove($file->getPathname());
                    ++$orphans;
                }
            }
        }

        if ($orphans > 0) {
            $io->note(sprintf('%d fichier(s) orphelin(s) supprime(s).', $orphans));
        }
    }
}
