<?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\Pagination\PaginatorFactoryInterface;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Chill\MainBundle\Repository\CenterRepositoryInterface;
use Chill\MainBundle\Repository\UserRepositoryInterface;
use Chill\MainBundle\Repository\UserGroupRepositoryInterface;
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\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Clock\MockClock;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;

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

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

        $ticketRepository = $this->prophesize(TicketACLAwareRepositoryInterface::class);
        $tickets = [new Ticket(), new Ticket()];

        // The date in RFC3339 format
        $dateString = '2025-05-15T15:05:00+00:00';
        $date = \DateTimeImmutable::createFromFormat(\DateTimeImmutable::RFC3339, $dateString);

        $ticketRepository->countTickets(
            Argument::that(
                fn ($params) => isset($params['byCreatedAfter'])
                && $params['byCreatedAfter'] == $date
            )
        )->willReturn(2);

        $ticketRepository->findTickets(
            Argument::that(
                fn ($params) => isset($params['byCreatedAfter'])
                && $params['byCreatedAfter'] == $date
            ),
            0,
            10
        )->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);

        // Create controller
        $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(),
            $this->prophesize(UserGroupRepositoryInterface::class)->reveal(),
            $this->prophesize(CenterRepositoryInterface::class)->reveal()
        );

        // Create request with byCreatedAfter filter in RFC3339 format
        $request = new Request(
            query: ['byCreatedAfter' => $dateString]
        );

        // Call controller method
        $response = $controller->listTicket($request);

        // Assert response
        $this->assertInstanceOf(JsonResponse::class, $response);
        $this->assertEquals('{"items":[{},{}],"pagination":{}}', $response->getContent());
    }

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

        $ticketRepository = $this->prophesize(TicketACLAwareRepositoryInterface::class);
        $tickets = [new Ticket(), new Ticket()];

        // The date in RFC3339_EXTENDED format
        $dateString = '2025-05-15T15:05:00.000+02:00';
        $date = \DateTimeImmutable::createFromFormat(\DateTimeImmutable::RFC3339_EXTENDED, $dateString);

        $ticketRepository->countTickets(
            Argument::that(
                fn ($params) => isset($params['byCreatedAfter'])
                && $params['byCreatedAfter'] == $date
            )
        )->willReturn(2);

        $ticketRepository->findTickets(
            Argument::that(
                fn ($params) => isset($params['byCreatedAfter'])
                && $params['byCreatedAfter'] == $date
            ),
            0,
            10
        )->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);

        // Create controller
        $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(),
            $this->prophesize(UserGroupRepositoryInterface::class)->reveal(),
            $this->prophesize(CenterRepositoryInterface::class)->reveal()
        );

        // Create request with byCreatedAfter filter in RFC3339_EXTENDED format
        $request = new Request(
            query: ['byCreatedAfter' => $dateString]
        );

        // Call controller method
        $response = $controller->listTicket($request);

        // Assert response
        $this->assertInstanceOf(JsonResponse::class, $response);
        $this->assertEquals('{"items":[{},{}],"pagination":{}}', $response->getContent());
    }

    public function testListTicketWithByCreatedAfterInvalidFormat(): void
    {
        self::expectException(BadRequestHttpException::class);
        self::expectExceptionMessage('Invalid date for byCreatedAfter');

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

        $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);
        $centerRepository = $this->prophesize(CenterRepositoryInterface::class);

        // Create controller
        $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(),
            $this->prophesize(UserGroupRepositoryInterface::class)->reveal(),
            $centerRepository->reveal(),
        );

        // Create request with byCreatedAfter filter in invalid format
        $request = new Request(
            query: ['byCreatedAfter' => '2025-05-15']
        );

        // Call controller method
        $controller->listTicket($request);
    }
}
