<?php

declare(strict_types=1);

namespace NoahVet\Reef\Command;

use NoahVet\Reef\Security\IAM\Finder\ResourceFinderManager;
use NoahVet\Reef\Security\IAM\Generator\IAMResourceGenerator;
use NoahVet\Reef\Security\Policy\PolicyManager;
use NoahVet\Reef\Security\Policy\PolicyManagerFactory;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class SyncPoliciesCommand extends Command
{
    protected ?string $reefServiceToken;

    protected IAMResourceGenerator $resourceGenerator;

    protected PolicyManager $policyManager;

    protected ResourceFinderManager $resourceIteratorFactory;

    public function __construct(
        ?string $reefServiceToken,
        IAMResourceGenerator $resourceGenerator,
        PolicyManagerFactory $policyManagerFactory,
        ResourceFinderManager $resourceFinderManager,
    ) {
        parent::__construct('reef:policies:sync');

        $this->reefServiceToken = $reefServiceToken;
        $this->resourceGenerator = $resourceGenerator;
        $this->policyManager = $policyManagerFactory->create($reefServiceToken ?? '');
        $this->resourceIteratorFactory = $resourceFinderManager;
    }

    protected function configure(): void
    {
        $this->addOption(
            'resource',
            'r',
            InputOption::VALUE_REQUIRED,
            'IAM Resource slug if you want to synchronize policies on'
                        ." one specific resource. Ex: 'reef:iam:principal:toto'",
        );
    }

    protected function syncResourceSlug(
        string $resourceSlug,
        OutputInterface $output,
    ): int {
        $rawResource = $this->resourceIteratorFactory->findBySlug($resourceSlug);

        if (!$rawResource) {
            $output->writeln("Can't find the specified resource");

            return 1;
        }

        // Add log
        $this->policyManager->syncPolicies($rawResource);

        return 0;
    }

    protected function syncAllResources(): int
    {
        // Step 1 : Find a resource iterator
        $resourceIterator = $this->resourceIteratorFactory->createIterator();

        // Step 2 : Sync policies to each resource
        foreach ($resourceIterator->iterate() as $resource) {
            // Add log
            $this->policyManager->syncPolicies($resource);
        }

        return 0;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        if (null === $this->reefServiceToken || empty($this->reefServiceToken)) {
            $output->writeln('No service token configured');

            return 1;
        }

        $resourceSlug = $input->getOption('resource');
        // Step 1 : Find a unique resource (if provided)
        if (null !== $resourceSlug && !empty($resourceSlug)) {
            return $this->syncResourceSlug($resourceSlug, $output);
        }

        return $this->syncAllResources();
    }
}
