<?php

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;
use Symfony\Component\Console\Style\SymfonyStyle;

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;
    }

    #[\Override]
    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(SymfonyStyle $io): int
    {
        // Step 1 : Find a resource iterator
        $resourceIterator = $this->resourceIteratorFactory->createIterator();

        // Step 2 : Sync policies to each resource
        /** @var object $resource */
        foreach ($resourceIterator->iterate() as $resource) {
            $resourceClass = $resource::class;
            $resourceId = \method_exists($resource, 'getId') ? (string) $resource->getId() : null;

            $io->writeln("Resource : {$resourceClass}#{$resourceId}", OutputInterface::VERBOSITY_VERBOSE);

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

        return 0;
    }

    #[\Override]
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);

        if (null === $this->reefServiceToken || empty($this->reefServiceToken)) {
            $io->error('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($io);
    }
}
