<?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\Workflow\EntityWorkflowStepSignature;
use Chill\MainBundle\Routing\ChillUrlGeneratorInterface;
use Chill\MainBundle\Security\Authorization\EntityWorkflowStepSignatureVoter;
use Chill\MainBundle\Workflow\SignatureStepStateChanger;
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\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
use Twig\Environment;

final readonly class WorkflowSignatureStateChangeController
{
    public function __construct(
        private EntityManagerInterface $entityManager,
        private Security $security,
        private FormFactoryInterface $formFactory,
        private Environment $twig,
        private SignatureStepStateChanger $signatureStepStateChanger,
        private ChillUrlGeneratorInterface $chillUrlGenerator,
    ) {}

    #[Route('/{_locale}/main/workflow/signature/{id}/cancel', name: 'chill_main_workflow_signature_cancel')]
    public function cancelSignature(EntityWorkflowStepSignature $signature, Request $request): Response
    {
        return $this->markSignatureAction(
            $signature,
            $request,
            EntityWorkflowStepSignatureVoter::CANCEL,
            fn (EntityWorkflowStepSignature $signature): string => $this->signatureStepStateChanger->markSignatureAsCanceled($signature),
            '@ChillMain/WorkflowSignature/cancel.html.twig',
        );
    }

    #[Route('/{_locale}/main/workflow/signature/{id}/reject', name: 'chill_main_workflow_signature_reject')]
    public function rejectSignature(EntityWorkflowStepSignature $signature, Request $request): Response
    {
        return $this->markSignatureAction(
            $signature,
            $request,
            EntityWorkflowStepSignatureVoter::REJECT,
            fn (EntityWorkflowStepSignature $signature): string => $this->signatureStepStateChanger->markSignatureAsRejected($signature),
            '@ChillMain/WorkflowSignature/reject.html.twig',
        );
    }

    /**
     * @param callable(EntityWorkflowStepSignature): string $markSignature
     *
     * @throws \Twig\Error\LoaderError
     * @throws \Twig\Error\RuntimeError
     * @throws \Twig\Error\SyntaxError
     */
    private function markSignatureAction(
        EntityWorkflowStepSignature $signature,
        Request $request,
        string $permissionAttribute,
        callable $markSignature,
        string $template,
    ): Response {

        if (!$this->security->isGranted($permissionAttribute, $signature)) {
            throw new AccessDeniedHttpException('not allowed to cancel this signature');
        }

        $form = $this->formFactory->create();
        $form->add('confirm', SubmitType::class, ['label' => 'Confirm']);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $expectedStep = $this->entityManager->wrapInTransaction(fn () => $markSignature($signature));

            return new RedirectResponse(
                $this->chillUrlGenerator->forwardReturnPath(
                    'chill_main_workflow_wait',
                    ['id' => $signature->getStep()->getEntityWorkflow()->getId(), 'expectedStep' => $expectedStep]
                )
            );
        }

        return
            new Response(
                $this->twig->render(
                    $template,
                    ['form' => $form->createView(), 'signature' => $signature]
                )
            );
    }
}
