<?php

namespace App\Tests\A_Unit\Adapter\Controller\Front\Registration\Store;

use Myvetshop\Module\Clinique\Adapter\Controller\Front\Registration\Store\StoreSearcherControllerAdapter;
use Myvetshop\Module\Clinique\Adapter\Repository\StoreRepository;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;

class StoreSearcherControllerAdapterTest extends TestCase
{
    /**
     * @var StoreRepository&MockObject
     */
    private StoreRepository $storeRepositoryMock;

    private StoreSearcherControllerAdapter $adapter;

    protected function setUp(): void
    {
        $this->storeRepositoryMock = $this->createMock(StoreRepository::class);
        $this->adapter = new StoreSearcherControllerAdapter($this->storeRepositoryMock);
    }

    public function testHandleRequestWithValidSearchParameter(): void
    {
        $request = new Request();
        $request->query->set('search', 'Test Store');

        $expectedResults = [['id' => 1, 'name' => 'Test Store']];
        $this->storeRepositoryMock
            ->expects($this->once())
            ->method('search')
            ->with('Test Store')
            ->willReturn($expectedResults);

        $ret = $this->adapter->handleRequest($this->createMock(\Context::class), $request);

        \assert(isset($ret['response']));
        $this->assertNotNull($ret['response']);

        $this->assertInstanceOf(\Symfony\Component\HttpFoundation\JsonResponse::class, $ret['response']);
        $responseData = \json_decode((string) $ret['response']->getContent(), true);

        $this->assertEquals($expectedResults, $responseData);
    }

    public function testHandleRequestWithoutSearchParameterReturnsAllStores(): void
    {
        $request = new Request();

        $expectedResults = [
            ['id' => 1, 'name' => 'Store 1'],
            ['id' => 2, 'name' => 'Store 2'],
        ];
        $this->storeRepositoryMock
            ->expects($this->once())
            ->method('findAll')
            ->willReturn($expectedResults);

        $ret = $this->adapter->handleRequest($this->createMock(\Context::class), $request);

        \assert(isset($ret['response']));
        $this->assertNotNull($ret['response']);

        $this->assertInstanceOf(\Symfony\Component\HttpFoundation\JsonResponse::class, $ret['response']);
        $responseData = \json_decode((string) $ret['response']->getContent(), true);

        $this->assertEquals($expectedResults, $responseData);
    }

    public function testHandleRequestWithInvalidQueryParametersThrowsException(): void
    {
        $this->expectException(InvalidOptionsException::class);

        $request = new Request();
        $request->query->set('search', ['Invalid Array']);

        $ret = $this->adapter->handleRequest($this->createMock(\Context::class), $request);

        \assert(isset($ret['response']));
        $this->assertNotNull($ret['response']);

        $this->assertInstanceOf(\Symfony\Component\HttpFoundation\JsonResponse::class, $ret['response']);
        $responseData = \json_decode((string) $ret['response']->getContent(), true);

        $this->assertEquals([], $responseData);
    }

    public function testHandleRequestWithStartAndLimitParameters(): void
    {
        $request = new Request();
        $request->query->set('start', 10);
        $request->query->set('limit', 5);

        $expectedResults = [
            ['id' => 11, 'name' => 'Store 11'],
            ['id' => 12, 'name' => 'Store 12'],
        ];
        $this->storeRepositoryMock
            ->expects($this->once())
            ->method('findAll')
            ->with(10, 5)
            ->willReturn($expectedResults);

        $ret = $this->adapter->handleRequest($this->createMock(\Context::class), $request);

        \assert(isset($ret['response']));
        $this->assertNotNull($ret['response']);

        $this->assertInstanceOf(\Symfony\Component\HttpFoundation\JsonResponse::class, $ret['response']);
        $responseData = \json_decode((string) $ret['response']->getContent(), true);

        $this->assertEquals($expectedResults, $responseData);
    }
}
