<?php

namespace NoahVet\Reef\Test\A_Unit\Domain\Security\Policy;

use NoahVet\Reef\Domain\Security\Model\Resource;
use NoahVet\Reef\Domain\Security\Model\ResourceType;
use NoahVet\Reef\Domain\Security\Policy\PolicyResult;
use NoahVet\Reef\Domain\Security\Policy\PolicyResultGrant;
use PHPUnit\Framework\TestCase;

class PolicyResultTest extends TestCase
{
    private ResourceType $resourceType;

    protected function setUp(): void
    {
        $this->resourceType = ResourceType::fromString('reef:phpunit:resource');
    }

    public function testConstructorMakesFieldsAccessible(): void
    {
        $result = new PolicyResult('my-policy', Resource::fromString($this->resourceType, 'subject-1'));

        self::assertSame('my-policy', $result->getPolicyName());
        self::assertSame('subject-1', $result->getSubject()->getResourceId());
        self::assertSame($this->resourceType, $result->getSubject()->getResourceType());
        self::assertSame([], $result->getGrants());
        self::assertNull($result->etag);
    }

    public function testAddGrantAppendsToGrantsList(): void
    {
        $result = new PolicyResult('my-policy', Resource::fromString($this->resourceType, 'subject-1'));
        $grant = new PolicyResultGrant(
            Resource::fromString($this->resourceType, 'res-1'),
            'reef:phpunit:principal:user',
            ['read'],
        );

        $result->addGrant($grant);

        self::assertCount(1, $result->getGrants());
        self::assertSame($grant, $result->getGrants()[0]);
    }

    public function testMultipleGrantsReturnedInOrder(): void
    {
        $result = new PolicyResult('my-policy', Resource::fromString($this->resourceType, 'subject-1'));
        $resource = Resource::fromString($this->resourceType, 'res-1');

        $grant1 = new PolicyResultGrant($resource, 'principal:a', ['read']);
        $grant2 = new PolicyResultGrant($resource, 'principal:b', ['write']);

        $result->addGrant($grant1);
        $result->addGrant($grant2);

        $grants = $result->getGrants();
        self::assertCount(2, $grants);
        self::assertSame($grant1, $grants[0]);
        self::assertSame($grant2, $grants[1]);
    }

    public function testEtagIsWritable(): void
    {
        $result = new PolicyResult('my-policy', Resource::fromString($this->resourceType, 'subject-1'));
        $result->etag = 'abc123';

        self::assertSame('abc123', $result->etag);
    }
}
