<?php

namespace NoahVet\Reef\Test\A_Unit\Infrastructure\Security\Service;

use NoahVet\Reef\Application\Security\Service\ResourceFinderService;
use NoahVet\Reef\Domain\Security\Port\ResourceEnumeratorInterface;
use NoahVet\Reef\Domain\Security\Port\ResourceLocatorInterface;
use PHPUnit\Framework\TestCase;

class ResourceFinderServiceTest extends TestCase
{
    public function testIterateYieldsFromEnumeratorsInOrder(): void
    {
        $enum1 = $this->createMock(ResourceEnumeratorInterface::class);
        $enum1->method('enumerate')->willReturnCallback(static function (): \Generator {
            yield 'item-a';
            yield 'item-b';
        });

        $enum2 = $this->createMock(ResourceEnumeratorInterface::class);
        $enum2->method('enumerate')->willReturnCallback(static function (): \Generator {
            yield 'item-c';
        });

        $service = new ResourceFinderService([$enum1, $enum2]);

        self::assertSame(['item-a', 'item-b', 'item-c'], \iterator_to_array($service->iterate(), false));
    }

    public function testIterateIgnoresLocatorOnlyFinders(): void
    {
        $locatorOnly = $this->createMock(ResourceLocatorInterface::class);
        $locatorOnly->expects(self::never())->method('findBySlug');

        $enumerator = $this->createMock(ResourceEnumeratorInterface::class);
        $enumerator->method('enumerate')->willReturnCallback(static function (): \Generator {
            yield 'item-a';
        });

        $service = new ResourceFinderService([$locatorOnly, $enumerator]);
        $items = \iterator_to_array($service->iterate(), false);

        self::assertSame(['item-a'], $items);
    }

    public function testFindBySlugReturnsFirstNonNullResult(): void
    {
        $locator1 = $this->createMock(ResourceLocatorInterface::class);
        $locator1->method('findBySlug')->with('reef:test:42')->willReturn(null);

        $locator2 = $this->createMock(ResourceLocatorInterface::class);
        $locator2->method('findBySlug')->with('reef:test:42')->willReturn('found-entity');

        $locator3 = $this->createMock(ResourceLocatorInterface::class);
        $locator3->expects(self::never())->method('findBySlug');

        $service = new ResourceFinderService([$locator1, $locator2, $locator3]);

        self::assertSame('found-entity', $service->findBySlug('reef:test:42'));
    }

    public function testFindBySlugReturnsNullIfNoLocatorMatches(): void
    {
        $locator1 = $this->createMock(ResourceLocatorInterface::class);
        $locator1->method('findBySlug')->willReturn(null);

        $locator2 = $this->createMock(ResourceLocatorInterface::class);
        $locator2->method('findBySlug')->willReturn(null);

        $service = new ResourceFinderService([$locator1, $locator2]);

        self::assertNull($service->findBySlug('reef:test:unknown'));
    }
}
