<?php

declare(strict_types=1);

namespace NoahVet\Reef\Test\A_Unit\Command;

use NoahVet\Reef\Command\SyncPoliciesCommand;
use NoahVet\Reef\Security\IAM\Finder\ResourceFinderEnumeratorInterface;
use NoahVet\Reef\Security\IAM\Finder\ResourceFinderManager;
use NoahVet\Reef\Security\IAM\Finder\ReverseResourceFinderInterface;
use NoahVet\Reef\Security\IAM\Generator\IAMResourceGenerator;
use NoahVet\Reef\Security\IAM\Model\Resource;
use NoahVet\Reef\Security\Policy\PolicyManager;
use NoahVet\Reef\Security\Policy\PolicyManagerFactory;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;

class SyncPoliciesCommandTest extends TestCase
{
    public function testExecuteAll(): void
    {
        $resourceA = Resource::fromString('reef:iam:testRt', 'testResource');

        $enumerator = \Mockery::mock(ResourceFinderEnumeratorInterface::class)
            ->shouldReceive('enumerate')
            ->withNoArgs()
            ->andYield($resourceA)
            ->getMock()
        ;

        $policyManager = $this->getMockBuilder(PolicyManager::class)
            ->disableOriginalConstructor()
            ->getMock()
        ;

        $policyManager
            ->method('syncPolicies')
            ->with($resourceA)
        ;

        $policyManagerFactory = $this->getMockBuilder(PolicyManagerFactory::class)
            ->disableOriginalConstructor()
            ->getMock()
        ;
        $policyManagerFactory
            ->method('create')
            ->withAnyParameters()
            ->willReturn($policyManager)
        ;

        $generator = $this->getMockBuilder(IAMResourceGenerator::class)
            ->disableOriginalConstructor()
            ->getMock()
        ;
        $generator
            ->expects($this->never())
            ->method('generate')
        ;

        $command = new SyncPoliciesCommand(
            'sample_token',
            $generator,
            $policyManagerFactory,
            new ResourceFinderManager([$enumerator]),
        );

        self::assertEquals(0, $command->run(new ArrayInput([]), new NullOutput()));
    }

    public function executeOneThatDontExists(): void
    {
        $enumerator = \Mockery::mock(ReverseResourceFinderInterface::class)
            ->shouldReceive('findBySlug')
            ->with('reef:api:testRt:testResource')
            ->andReturnNull()
            ->getMock()
        ;

        $policyManager = $this->getMockBuilder(PolicyManager::class)
            ->disableOriginalConstructor()
            ->getMock()
        ;

        $policyManager
            ->expects($this->never())
            ->method('syncPolicies')
        ;

        $policyManagerFactory = $this->getMockBuilder(PolicyManagerFactory::class)
            ->disableOriginalConstructor()
            ->getMock()
        ;
        $policyManagerFactory
            ->method('create')
            ->withAnyParameters()
            ->willReturn($policyManager)
        ;

        $generator = $this->getMockBuilder(IAMResourceGenerator::class)
            ->disableOriginalConstructor()
            ->getMock()
        ;
        $generator
            ->expects($this->never())
            ->method('generate')
        ;

        $command = new SyncPoliciesCommand(
            'sample_token',
            $generator,
            $policyManagerFactory,
            new ResourceFinderManager([$enumerator]),
        );

        self::assertEquals(0, $command->run(new ArrayInput(['--resource' => 'reef:api:testRt:testResource']), new NullOutput()));
    }

    public function executeOneThatExists(): void
    {
        $enumerator = \Mockery::mock(ReverseResourceFinderInterface::class)
            ->shouldReceive('findBySlug')
            ->with('reef:api:testRt:testResource')
            ->andReturn('testResource')
            ->getMock()
        ;

        $policyManager = $this->getMockBuilder(PolicyManager::class)
            ->disableOriginalConstructor()
            ->getMock()
        ;

        $policyManager
            ->expects($this->once())
            ->method('syncPolicies')
            ->with()
        ;

        $policyManagerFactory = $this->getMockBuilder(PolicyManagerFactory::class)
            ->disableOriginalConstructor()
            ->getMock()
        ;
        $policyManagerFactory
            ->method('create')
            ->withAnyParameters()
            ->willReturn($policyManager)
        ;

        $generator = $this->getMockBuilder(IAMResourceGenerator::class)
            ->disableOriginalConstructor()
            ->getMock()
        ;
        $generator
            ->expects($this->once())
            ->method('generate')
            ->with('testResource')
            ->willReturn([Resource::fromString('reef:api:testRt', 'testResource')])
        ;

        $command = new SyncPoliciesCommand(
            'sample_token',
            $generator,
            $policyManagerFactory,
            new ResourceFinderManager([$enumerator]),
        );

        self::assertEquals(0, $command->run(new ArrayInput(['--resource' => 'reef:api:testRt:testResource']), new NullOutput()));
    }
}
