<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\MainBundle\Controller;

use Chill\MainBundle\Entity\ExportGeneration;
use Chill\MainBundle\Entity\SavedExport;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Export\ExportDescriptionHelper;
use Chill\MainBundle\Export\ExportManager;
use Chill\MainBundle\Form\SavedExportType;
use Chill\MainBundle\Security\Authorization\ExportGenerationVoter;
use Chill\MainBundle\Security\Authorization\SavedExportVoter;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Translation\TranslatableMessage;
use Symfony\Contracts\Translation\TranslatableInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

final readonly class SavedExportController
{
    public function __construct(
        private \Twig\Environment $templating,
        private EntityManagerInterface $entityManager,
        private ExportManager $exportManager,
        private FormFactoryInterface $formFactory,
        private Security $security,
        private TranslatorInterface $translator,
        private UrlGeneratorInterface $urlGenerator,
        private ExportDescriptionHelper $exportDescriptionHelper,
    ) {}

    #[Route(path: '/{_locale}/exports/saved/{id}/delete', name: 'chill_main_export_saved_delete')]
    public function delete(SavedExport $savedExport, Request $request): Response
    {
        if (!$this->security->isGranted(SavedExportVoter::DELETE, $savedExport)) {
            throw new AccessDeniedHttpException();
        }

        $form = $this->formFactory->create();
        $form->add('submit', SubmitType::class, ['label' => 'Delete']);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $this->entityManager->remove($savedExport);
            $this->entityManager->flush();

            $session = $request->getSession();
            if ($session instanceof Session) {
                $session->getFlashBag()->add('success', new TranslatableMessage('saved_export.Export is deleted'));
            }

            return new RedirectResponse(
                $this->urlGenerator->generate('chill_main_export_saved_list_my')
            );
        }

        return new Response(
            $this->templating->render(
                '@ChillMain/SavedExport/delete.html.twig',
                [
                    'saved_export' => $savedExport,
                    'delete_form' => $form->createView(),
                ]
            )
        );
    }

    #[Route(path: '/exports/saved/create-from-export-generation/{id}/new', name: 'chill_main_export_saved_create_from_export_generation')]
    public function createFromExportGeneration(ExportGeneration $exportGeneration, Request $request): Response
    {
        if (!$this->security->isGranted(ExportGenerationVoter::VIEW, $exportGeneration)) {
            throw new AccessDeniedHttpException();
        }

        $user = $this->security->getUser();
        if (!$user instanceof User) {
            throw new AccessDeniedHttpException('only regular user can create a saved export');
        }

        $export = $this->exportManager->getExport($exportGeneration->getExportAlias());
        $title = $export->getTitle() instanceof TranslatableInterface ? $export->getTitle()->trans($this->translator) :
            $this->translator->trans($export->getTitle());

        $savedExport = new SavedExport();
        $savedExport
            ->setExportAlias($exportGeneration->getExportAlias())
            ->setUser($user)
            ->setOptions($exportGeneration->getOptions())
            ->setTitle(
                $request->query->has('title') ? $request->query->get('title') : $title
            );

        if ($exportGeneration->isLinkedToSavedExport()) {
            $savedExport->setDescription($exportGeneration->getSavedExport()->getDescription());
        } else {
            $savedExport->setDescription(
                implode(
                    "\n",
                    array_map(
                        fn (string $item) => '- '.$item."\n",
                        $this->exportDescriptionHelper->describe($savedExport->getExportAlias(), $savedExport->getOptions(), includeExportTitle: false)
                    )
                )
            );
        }

        return $this->handleEdit($savedExport, $request, true);
    }

    #[Route(path: '/exports/saved/duplicate-from-saved-export/{id}/new', name: 'chill_main_export_saved_duplicate')]
    public function duplicate(SavedExport $previousSavedExport, Request $request): Response
    {
        $user = $this->security->getUser();
        if (!$user instanceof User) {
            throw new AccessDeniedHttpException('only regular user can create a saved export');
        }

        if (!$this->security->isGranted(SavedExportVoter::EDIT, $previousSavedExport)) {
            throw new AccessDeniedHttpException('Not allowed to edit this saved export');
        }

        $savedExport = new SavedExport();
        $savedExport
            ->setExportAlias($previousSavedExport->getExportAlias())
            ->setUser($user)
            ->setOptions($previousSavedExport->getOptions())
            ->setDescription($previousSavedExport->getDescription())
            ->setTitle(
                $request->query->has('title') ?
                    $request->query->get('title') :
                    $previousSavedExport->getTitle().' ('.$this->translator->trans('saved_export.Duplicated').' '.(new \DateTimeImmutable('now'))->format('d-m-Y H:i:s').')'
            );

        return $this->handleEdit($savedExport, $request);

    }

    private function handleEdit(SavedExport $savedExport, Request $request, bool $showWarningAutoGeneratedDescription = false): Response
    {
        $form = $this->formFactory->create(SavedExportType::class, $savedExport);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $this->entityManager->persist($savedExport);
            $this->entityManager->flush();

            if (($session = $request->getSession()) instanceof Session) {
                $session->getFlashBag()->add('success', new TranslatableMessage('saved_export.Saved export is saved!'));
            }

            return new RedirectResponse(
                $this->urlGenerator->generate('chill_main_export_saved_list_my'),
            );
        }

        return new Response(
            $this->templating->render(
                '@ChillMain/SavedExport/new.html.twig',
                [
                    'form' => $form->createView(),
                    'showWarningAutoGeneratedDescription' => $showWarningAutoGeneratedDescription,
                ],
            ),
        );
    }

    #[Route(path: '/{_locale}/exports/saved/{id}/edit', name: 'chill_main_export_saved_edit')]
    public function edit(SavedExport $savedExport, Request $request): Response
    {
        if (!$this->security->isGranted(SavedExportVoter::EDIT, $savedExport)) {
            throw new AccessDeniedHttpException();
        }

        $form = $this->formFactory->create(SavedExportType::class, $savedExport);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $this->entityManager->flush();

            if (($session = $request->getSession()) instanceof Session) {
                $session->getFlashBag()->add('success', new TranslatableMessage('saved_export.Saved export is saved!'));
            }

            return new RedirectResponse(
                $this->urlGenerator->generate('chill_main_export_saved_list_my'),
            );
        }

        return new Response(
            $this->templating->render(
                '@ChillMain/SavedExport/edit.html.twig',
                [
                    'form' => $form->createView(),
                ],
            ),
        );
    }

    #[Route(path: '/{_locale}/exports/saved/{savedExport}/edit-options/{exportGeneration}', name: 'chill_main_export_saved_options_edit')]
    public function updateOptionsFromGeneration(SavedExport $savedExport, ExportGeneration $exportGeneration, Request $request): Response
    {
        if (!$this->security->isGranted(SavedExportVoter::DUPLICATE, $savedExport)) {
            throw new AccessDeniedHttpException('You are not allowed to access this saved export');
        }

        if (!$this->security->isGranted(ExportGenerationVoter::VIEW, $exportGeneration)) {
            throw new AccessDeniedHttpException('You are not allowed to access this export generation');
        }

        if ($savedExport->getExportAlias() !== $exportGeneration->getExportAlias()) {
            throw new UnprocessableEntityHttpException('export alias does not match');
        }

        $savedExport->setOptions($exportGeneration->getOptions());

        $this->entityManager->flush();

        $session = $request->getSession();
        if ($session instanceof Session) {
            $session->getFlashBag()->add('success', new TranslatableMessage('saved_export.Options updated successfully'));
        }

        return new RedirectResponse(
            $this->urlGenerator->generate('chill_main_export_saved_edit', ['id' => $savedExport->getId()]),
        );
    }
}
