<?php

namespace App\Tests\Service;

use App\Entity\BilletBuyer;
use App\Entity\BilletBuyerItem;
use App\Entity\Event;
use App\Entity\User;
use App\Repository\BilletBuyerRepository;
use App\Service\MeilisearchService;
use App\Service\OrderIndexService;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;

class OrderIndexServiceTest extends TestCase
{
    private function createMocks(): array
    {
        $meilisearch = $this->createMock(MeilisearchService::class);
        $em = $this->createMock(EntityManagerInterface::class);

        return [$meilisearch, $em, new OrderIndexService($meilisearch, $em)];
    }

    private function createOrder(): BilletBuyer
    {
        $user = new User();
        $user->setEmail('orga@test.fr');
        $user->setFirstName('Test');
        $user->setLastName('Orga');
        $user->setPassword('hashed');

        $event = new Event();
        $event->setAccount($user);
        $event->setTitle('Test Event');
        $event->setStartAt(new \DateTimeImmutable());
        $event->setEndAt(new \DateTimeImmutable('+1 day'));
        $event->setAddress('1 rue');
        $event->setZipcode('75001');
        $event->setCity('Paris');

        $order = new BilletBuyer();
        $order->setEvent($event);
        $order->setFirstName('Jean');
        $order->setLastName('Dupont');
        $order->setEmail('jean@test.fr');
        $order->setOrderNumber('2026-03-21-1');
        $order->setTotalHT(1500);

        $item = new BilletBuyerItem();
        $item->setBilletName('Entree VIP');
        $item->setQuantity(2);
        $order->addItem($item);

        return $order;
    }

    public function testSearchOrdersReturnsEmptyOnEmptyQuery(): void
    {
        [$meilisearch, $em, $service] = $this->createMocks();

        $meilisearch->expects(self::never())->method('search');

        $result = $service->searchOrders(1, '');

        self::assertSame([], $result);
    }

    public function testSearchOrdersReturnResultsFromMeilisearch(): void
    {
        [$meilisearch, $em, $service] = $this->createMocks();

        $order = $this->createOrder();

        $meilisearch->expects(self::once())
            ->method('search')
            ->with('order_event_1', 'dupont')
            ->willReturn(['hits' => [['id' => 42]]]);

        $repo = $this->createMock(BilletBuyerRepository::class);
        $repo->expects(self::once())
            ->method('findBy')
            ->with(['id' => [42]])
            ->willReturn([$order]);

        $em->expects(self::once())
            ->method('getRepository')
            ->with(BilletBuyer::class)
            ->willReturn($repo);

        $result = $service->searchOrders(1, 'dupont');

        self::assertCount(1, $result);
    }

    public function testSearchOrdersReturnsEmptyOnNoHits(): void
    {
        [$meilisearch, $em, $service] = $this->createMocks();

        $meilisearch->expects(self::once())
            ->method('search')
            ->willReturn(['hits' => []]);

        $result = $service->searchOrders(1, 'inexistant');

        self::assertSame([], $result);
    }

    public function testSearchOrdersReturnsEmptyOnException(): void
    {
        [$meilisearch, $em, $service] = $this->createMocks();

        $meilisearch->expects(self::once())
            ->method('search')
            ->willThrowException(new \RuntimeException('Meilisearch down'));

        $result = $service->searchOrders(1, 'test');

        self::assertSame([], $result);
    }

    public function testIndexOrder(): void
    {
        [$meilisearch, $em, $service] = $this->createMocks();

        $order = $this->createOrder();

        $meilisearch->expects(self::once())->method('createIndexIfNotExists');
        $meilisearch->expects(self::once())->method('addDocuments');

        $service->indexOrder($order);
    }

    public function testIndexOrderHandlesException(): void
    {
        [$meilisearch, $em, $service] = $this->createMocks();

        $order = $this->createOrder();

        $meilisearch->expects(self::once())
            ->method('createIndexIfNotExists')
            ->willThrowException(new \RuntimeException('Meilisearch down'));

        $service->indexOrder($order);

        // No exception thrown
        self::assertTrue(true);
    }
}
