<?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\TicketBundle\Tests\Controller;

use Chill\MainBundle\Entity\UserGroup;
use Chill\MainBundle\Pagination\PaginatorFactoryInterface;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Chill\MainBundle\Repository\CenterRepositoryInterface;
use Chill\MainBundle\Repository\UserGroupRepositoryInterface;
use Chill\MainBundle\Repository\UserRepositoryInterface;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\PersonBundle\Repository\PersonRepository;
use Chill\TicketBundle\Controller\TicketListApiController;
use Chill\TicketBundle\Entity\Ticket;
use Chill\TicketBundle\Repository\MotiveRepository;
use Chill\TicketBundle\Repository\TicketACLAwareRepositoryInterface;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\Clock\MockClock;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\SerializerInterface;

/**
 * @internal
 *
 * @covers \Chill\TicketBundle\Controller\TicketListApiController
 */
final class TicketListApiControllerByAddresseeGroupTest extends TestCase
{
    use ProphecyTrait;

    public function testListTicketWithSingleByAddresseeGroupFilter(): void
    {
        // Mocks
        $security = $this->prophesize(Security::class);
        $security->isGranted('ROLE_USER')->willReturn(true);

        $group = new UserGroup();

        $groupRepository = $this->prophesize(UserGroupRepositoryInterface::class);
        $groupRepository->find(10)->willReturn($group);

        $ticketRepository = $this->prophesize(TicketACLAwareRepositoryInterface::class);
        $tickets = [new Ticket(), new Ticket()];
        $ticketRepository->countTickets(
            Argument::that(fn ($params) => isset($params['byAddresseeGroup']) && in_array($group, $params['byAddresseeGroup'], true))
        )->shouldBeCalled()->willReturn(2);
        $ticketRepository->findTickets(
            Argument::that(fn ($params) => isset($params['byAddresseeGroup']) && in_array($group, $params['byAddresseeGroup'], true)),
            0,
            10
        )->shouldBeCalled()->willReturn($tickets);

        $paginator = $this->prophesize(PaginatorInterface::class);
        $paginator->getCurrentPageFirstItemNumber()->willReturn(0);
        $paginator->getItemsPerPage()->willReturn(10);

        $paginatorFactory = $this->prophesize(PaginatorFactoryInterface::class);
        $paginatorFactory->create(2)->willReturn($paginator->reveal());

        $serializer = $this->prophesize(SerializerInterface::class);
        $serializer->serialize(
            Argument::that(fn (Collection $collection) => $collection->getItems() === $tickets),
            'json',
            ['groups' => 'read:simple']
        )->willReturn('{"items":[{},{}],"pagination":{}}');

        $personRepository = $this->prophesize(PersonRepository::class);
        $motiveRepository = $this->prophesize(MotiveRepository::class);
        $userRepository = $this->prophesize(UserRepositoryInterface::class);

        $controller = new TicketListApiController(
            $security->reveal(),
            $ticketRepository->reveal(),
            $paginatorFactory->reveal(),
            $serializer->reveal(),
            $personRepository->reveal(),
            $motiveRepository->reveal(),
            new MockClock(),
            new ParameterBag(['chill_ticket' => ['ticket' => ['response_time_exceeded_delay' => 'PT12H']]]),
            $userRepository->reveal(),
            $groupRepository->reveal(),
            $this->prophesize(CenterRepositoryInterface::class)->reveal(),
        );

        $request = new Request(query: ['byAddresseeGroup' => '10']);

        $response = $controller->listTicket($request);

        self::assertInstanceOf(JsonResponse::class, $response);
        self::assertSame('{"items":[{},{}],"pagination":{}}', $response->getContent());
    }

    public function testListTicketWithMultipleByAddresseeGroupFilter(): void
    {
        $security = $this->prophesize(Security::class);
        $security->isGranted('ROLE_USER')->willReturn(true);

        $group1 = new UserGroup();
        $group2 = new UserGroup();

        $groupRepository = $this->prophesize(UserGroupRepositoryInterface::class);
        $groupRepository->find(10)->willReturn($group1);
        $groupRepository->find(20)->willReturn($group2);

        $ticketRepository = $this->prophesize(TicketACLAwareRepositoryInterface::class);
        $tickets = [new Ticket(), new Ticket()];
        $ticketRepository->countTickets(
            Argument::that(fn ($params) => isset($params['byAddresseeGroup'])
                && in_array($group1, $params['byAddresseeGroup'], true)
                && in_array($group2, $params['byAddresseeGroup'], true))
        )->shouldBeCalled()->willReturn(2);
        $ticketRepository->findTickets(
            Argument::that(fn ($params) => isset($params['byAddresseeGroup'])
                && in_array($group1, $params['byAddresseeGroup'], true)
                && in_array($group2, $params['byAddresseeGroup'], true)),
            0,
            10
        )->shouldBeCalled()->willReturn($tickets);

        $paginator = $this->prophesize(PaginatorInterface::class);
        $paginator->getCurrentPageFirstItemNumber()->willReturn(0);
        $paginator->getItemsPerPage()->willReturn(10);

        $paginatorFactory = $this->prophesize(PaginatorFactoryInterface::class);
        $paginatorFactory->create(2)->willReturn($paginator->reveal());

        $serializer = $this->prophesize(SerializerInterface::class);
        $serializer->serialize(
            Argument::that(fn (Collection $collection) => $collection->getItems() === $tickets),
            'json',
            ['groups' => 'read:simple']
        )->willReturn('{"items":[{},{}],"pagination":{}}');

        $personRepository = $this->prophesize(PersonRepository::class);
        $motiveRepository = $this->prophesize(MotiveRepository::class);
        $userRepository = $this->prophesize(UserRepositoryInterface::class);

        $controller = new TicketListApiController(
            $security->reveal(),
            $ticketRepository->reveal(),
            $paginatorFactory->reveal(),
            $serializer->reveal(),
            $personRepository->reveal(),
            $motiveRepository->reveal(),
            new MockClock(),
            new ParameterBag(['chill_ticket' => ['ticket' => ['response_time_exceeded_delay' => 'PT12H']]]),
            $userRepository->reveal(),
            $groupRepository->reveal(),
            $this->prophesize(CenterRepositoryInterface::class)->reveal(),
        );

        $request = new Request(query: ['byAddresseeGroup' => '10,20']);

        $response = $controller->listTicket($request);

        self::assertInstanceOf(JsonResponse::class, $response);
        self::assertSame('{"items":[{},{}],"pagination":{}}', $response->getContent());
    }

    public function testListTicketWithByAddresseeGroupFilterGroupNotFound(): void
    {
        self::expectException(BadRequestHttpException::class);
        self::expectExceptionMessage('User group not found');

        $security = $this->prophesize(Security::class);
        $security->isGranted('ROLE_USER')->willReturn(true);

        $group1 = new UserGroup();

        $groupRepository = $this->prophesize(UserGroupRepositoryInterface::class);
        $groupRepository->find(10)->willReturn($group1);
        $groupRepository->find(20)->willReturn(null); // not found

        $ticketRepository = $this->prophesize(TicketACLAwareRepositoryInterface::class);
        $paginatorFactory = $this->prophesize(PaginatorFactoryInterface::class);
        $serializer = $this->prophesize(SerializerInterface::class);
        $personRepository = $this->prophesize(PersonRepository::class);
        $motiveRepository = $this->prophesize(MotiveRepository::class);
        $userRepository = $this->prophesize(UserRepositoryInterface::class);

        $controller = new TicketListApiController(
            $security->reveal(),
            $ticketRepository->reveal(),
            $paginatorFactory->reveal(),
            $serializer->reveal(),
            $personRepository->reveal(),
            $motiveRepository->reveal(),
            new MockClock(),
            new ParameterBag(['chill_ticket' => ['ticket' => ['response_time_exceeded_delay' => 'PT12H']]]),
            $userRepository->reveal(),
            $groupRepository->reveal(),
            $this->prophesize(CenterRepositoryInterface::class)->reveal(),
        );

        $request = new Request(query: ['byAddresseeGroup' => '10,20']);

        // should throw
        $controller->listTicket($request);
    }
}
