<?php

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

use NoahVet\Reef\Iam\Client;
use NoahVet\Reef\Iam\Model\PolicyResult;
use NoahVet\Reef\Infrastructure\Security\Api\JanePolicyResultStore;
use PHPUnit\Framework\TestCase;

class JanePolicyResultStoreTest extends TestCase
{
    private Client $client;

    protected function setUp(): void
    {
        $this->client = $this->createMock(Client::class);
    }

    public function testFindEtagReturnsEtagWhenFound(): void
    {
        $stored = (new PolicyResult())
            ->setName('test-policy')
            ->setSubject('subject-1')
            ->setEtag('etag-abc')
        ;

        $this->client
            ->method('getPolicyResultCollection')
            ->with([
                'name' => 'test-policy',
                'subject' => 'subject-1',
            ], [])
            ->willReturn([$stored])
        ;

        $store = new JanePolicyResultStore($this->client, []);

        self::assertSame('etag-abc', $store->findEtag('test-policy', 'subject-1'));
    }

    public function testFindEtagReturnsNullWhenNotFound(): void
    {
        $this->client
            ->method('getPolicyResultCollection')
            ->willReturn([])
        ;

        $store = new JanePolicyResultStore($this->client, []);

        self::assertNull($store->findEtag('test-policy', 'subject-missing'));
    }

    public function testFindEtagsReturnsSubjectToEtagMap(): void
    {
        $result1 = (new PolicyResult())
            ->setSubject('subject-a')
            ->setEtag('etag-a')
        ;
        $result2 = (new PolicyResult())
            ->setSubject('subject-b')
            ->setEtag('etag-b')
        ;

        $this->client
            ->method('getPolicyResultCollection')
            ->willReturnOnConsecutiveCalls(
                [$result1, $result2],
                [],
            )
        ;

        $store = new JanePolicyResultStore($this->client, []);
        $etags = $store->findEtags('test-policy', ['subject-a', 'subject-b']);

        self::assertSame([
            'subject-a' => 'etag-a',
            'subject-b' => 'etag-b',
        ], $etags);
    }

    public function testFindEtagsAggregatesMultiplePages(): void
    {
        $page1 = (new PolicyResult())
            ->setSubject('subject-a')
            ->setEtag('etag-a')
        ;
        $page2 = (new PolicyResult())
            ->setSubject('subject-b')
            ->setEtag('etag-b')
        ;

        $this->client
            ->method('getPolicyResultCollection')
            ->withConsecutive(
                [['name' => 'test-policy', 'subject[]' => ['subject-a', 'subject-b'], 'page' => 1]],
                [['name' => 'test-policy', 'subject[]' => ['subject-a', 'subject-b'], 'page' => 2]],
                [['name' => 'test-policy', 'subject[]' => ['subject-a', 'subject-b'], 'page' => 3]],
            )
            ->willReturnOnConsecutiveCalls(
                [$page1],
                [$page2],
                [],
            )
        ;

        $store = new JanePolicyResultStore($this->client, []);
        $etags = $store->findEtags('test-policy', ['subject-a', 'subject-b']);

        self::assertSame([
            'subject-a' => 'etag-a',
            'subject-b' => 'etag-b',
        ], $etags);
    }
}
