<?php

namespace NoahVet\Reef\Test\A_Unit\Application\Security\UseCase;

use NoahVet\Reef\Application\Security\Service\PolicyOrchestratorInterface;
use NoahVet\Reef\Application\Security\UseCase\ExecutePoliciesUseCase;
use NoahVet\Reef\Domain\Security\Model\ResourceType;
use NoahVet\Reef\Domain\Security\Policy\PolicyInterface;
use NoahVet\Reef\Domain\Security\Policy\PolicyResult;
use PHPUnit\Framework\TestCase;

class ExecutePoliciesUseCaseTest extends TestCase
{
    public function testNoPoliciesApplicableReturnsEmptyArray(): void
    {
        $orchestrator = $this->createMock(PolicyOrchestratorInterface::class);
        $subject = new \stdClass();

        $orchestrator
            ->method('getPoliciesFor')
            ->with($subject)
            ->willReturn([])
        ;

        $useCase = new ExecutePoliciesUseCase($orchestrator);

        self::assertSame([], $useCase->execute($subject));
    }

    public function testOnePolicyApplicableReturnsSingleResult(): void
    {
        $subject = new \stdClass();
        $expectedResult = new PolicyResult('test-policy', 'subject-1', ResourceType::fromString('reef:test'));

        $policy = $this->createMock(PolicyInterface::class);
        $policy->method('apply')->with($subject)->willReturn($expectedResult);

        $orchestrator = $this->createMock(PolicyOrchestratorInterface::class);
        $orchestrator->method('getPoliciesFor')->with($subject)->willReturn([$policy]);

        $useCase = new ExecutePoliciesUseCase($orchestrator);
        $results = $useCase->execute($subject);

        self::assertCount(1, $results);
        self::assertSame($expectedResult, $results[0]);
    }

    public function testMultiplePoliciesReturnAllResults(): void
    {
        $subject = new \stdClass();
        $resourceType = ResourceType::fromString('reef:test');
        $result1 = new PolicyResult('policy-a', 'subject-1', $resourceType);
        $result2 = new PolicyResult('policy-b', 'subject-1', $resourceType);

        $policy1 = $this->createMock(PolicyInterface::class);
        $policy1->method('apply')->willReturn($result1);

        $policy2 = $this->createMock(PolicyInterface::class);
        $policy2->method('apply')->willReturn($result2);

        $orchestrator = $this->createMock(PolicyOrchestratorInterface::class);
        $orchestrator->method('getPoliciesFor')->willReturn([$policy1, $policy2]);

        $useCase = new ExecutePoliciesUseCase($orchestrator);
        $results = $useCase->execute($subject);

        self::assertCount(2, $results);
        self::assertSame($result1, $results[0]);
        self::assertSame($result2, $results[1]);
    }
}
