<?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\CRUD\Controller\ApiController;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\MainBundle\Serializer\Model\Counter;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\SerializerInterface;

class WorkflowApiController extends ApiController
{
    public function __construct(private readonly EntityManagerInterface $entityManager, private readonly EntityWorkflowRepository $entityWorkflowRepository, private readonly PaginatorFactory $paginatorFactory, private readonly Security $security, private readonly SerializerInterface $serializer) {}

    /**
     * Return a list of workflow which are waiting an action for the user.
     */
    #[Route(path: '/api/1.0/main/workflow/my', methods: ['GET'])]
    public function myWorkflow(Request $request): JsonResponse
    {
        if (!$this->security->isGranted('ROLE_USER') || !$this->security->getUser() instanceof User) {
            throw new AccessDeniedException();
        }

        $total = $this->entityWorkflowRepository->countByDest($this->security->getUser());

        if ($request->query->getBoolean('countOnly', false)) {
            return new JsonResponse(
                $this->serializer->serialize(new Counter($total), 'json'),
                JsonResponse::HTTP_OK,
                [],
                true
            );
        }

        $paginator = $this->paginatorFactory->create($total);

        $workflows = $this->entityWorkflowRepository->findByDest(
            $this->security->getUser(),
            ['id' => 'DESC'],
            $paginator->getItemsPerPage(),
            $paginator->getCurrentPageFirstItemNumber()
        );

        return new JsonResponse(
            $this->serializer->serialize(new Collection($workflows, $paginator), 'json', ['groups' => ['read']]),
            JsonResponse::HTTP_OK,
            [],
            true
        );
    }

    /**
     * Return a list of workflow which are waiting an action for the user.
     */
    #[Route(path: '/api/1.0/main/workflow/my-cc', methods: ['GET'])]
    public function myWorkflowCc(Request $request): JsonResponse
    {
        if (!$this->security->isGranted('ROLE_USER') || !$this->security->getUser() instanceof User) {
            throw new AccessDeniedException();
        }

        $total = $this->entityWorkflowRepository->countByCc($this->security->getUser());

        if ($request->query->getBoolean('countOnly', false)) {
            return new JsonResponse(
                $this->serializer->serialize(new Counter($total), 'json'),
                JsonResponse::HTTP_OK,
                [],
                true
            );
        }

        $paginator = $this->paginatorFactory->create($total);

        $workflows = $this->entityWorkflowRepository->findByCc(
            $this->security->getUser(),
            ['id' => 'DESC'],
            $paginator->getItemsPerPage(),
            $paginator->getCurrentPageFirstItemNumber()
        );

        return new JsonResponse(
            $this->serializer->serialize(new Collection($workflows, $paginator), 'json', ['groups' => ['read']]),
            JsonResponse::HTTP_OK,
            [],
            true
        );
    }

    #[Route(path: '/api/1.0/main/workflow/{id}/subscribe', methods: ['POST'])]
    public function subscribe(EntityWorkflow $entityWorkflow, Request $request): Response
    {
        return $this->handleSubscription($entityWorkflow, $request, 'subscribe');
    }

    #[Route(path: '/api/1.0/main/workflow/{id}/unsubscribe', methods: ['POST'])]
    public function unsubscribe(EntityWorkflow $entityWorkflow, Request $request): Response
    {
        return $this->handleSubscription($entityWorkflow, $request, 'unsubscribe');
    }

    private function handleSubscription(EntityWorkflow $entityWorkflow, Request $request, string $action): JsonResponse
    {
        if (!$this->security->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
            throw new AccessDeniedException();
        }

        if (!$request->query->has('subscribe')) {
            throw new BadRequestHttpException('missing subscribe parameter');
        }

        $user = $this->security->getUser();

        match ($request->query->get('subscribe')) {
            'final' => match ($action) {
                'subscribe' => $entityWorkflow->addSubscriberToFinal($user),
                'unsubscribe' => $entityWorkflow->removeSubscriberToFinal($user),
                default => throw new \LogicException(),
            },
            'step' => match ($action) {
                'subscribe' => $entityWorkflow->addSubscriberToStep($user),
                'unsubscribe' => $entityWorkflow->removeSubscriberToStep($user),
                default => throw new \LogicException(),
            },
            default => throw new BadRequestHttpException('subscribe parameter must be equal to "step" or "final"'),
        };

        $this->entityManager->flush();

        return new JsonResponse(
            [
                'step' => $entityWorkflow->isUserSubscribedToStep($user),
                'final' => $entityWorkflow->isUserSubscribedToFinal($user),
            ],
            JsonResponse::HTTP_OK,
            [],
            false
        );
    }
}
