<?php

declare(strict_types=1);

namespace NoahVet\Reef\Command;

use NoahVet\Reef\Factory\ClientFactory;
use NoahVet\Reef\Jane\Exception\UnexpectedStatusCodeException;
use NoahVet\Reef\Jane\Model\ServiceDefinition;
use NoahVet\Reef\Jane\Normalizer\ServiceDefinitionNormalizer;
use NoahVet\Reef\Jane\Normalizer\ServiceExternalResourceNormalizer;
use NoahVet\Reef\Jane\Normalizer\ServicePermissionNormalizer;
use NoahVet\Reef\Jane\Normalizer\ServiceResourceNormalizer;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Serializer;

#[AsCommand(
    name: 'reef:service-definition:sync',
    description: 'Sync a service definition with the Reef IAM service',
)]
class SyncServiceDefinitionCommand extends Command
{
    public function __construct(
        private readonly ?string $reefServiceToken,
        private readonly ClientFactory $clientFactory,
    ) {
        parent::__construct();
    }

    protected function configure(): void
    {
        $this->addArgument(
            'service_definition_file',
            InputArgument::REQUIRED,
            'Path to the service definition file',
        );
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $styledOutput = new SymfonyStyle($input, $output);

        if (null === $this->reefServiceToken || empty($this->reefServiceToken)) {
            $styledOutput->error('No service token configured');

            return Command::FAILURE;
        }

        $serviceDefinitionFile = $input->getArgument('service_definition_file');
        if (!\is_file($serviceDefinitionFile)) {
            $styledOutput->error('Service definition file not found');

            return Command::FAILURE;
        }

        $serializer = new Serializer(
            [
                new ServiceDefinitionNormalizer(),
                new ServicePermissionNormalizer(),
                new ServiceResourceNormalizer(),
                new ServiceExternalResourceNormalizer(),
            ],
            [
                new JsonEncoder(),
            ],
        );

        $serviceDefinition = $serializer->deserialize(
            \file_get_contents($serviceDefinitionFile),
            ServiceDefinition::class,
            'json',
        );

        $client = $this->clientFactory->create($this->reefServiceToken);

        try {
            $client->putDefinitionClientItem($serviceDefinition->getId(), $serviceDefinition);
        } catch (\Exception $e) {
            if ($e instanceof UnexpectedStatusCodeException && 304 === $e->getCode()) {
                $styledOutput->success('Service definition already synced');

                return Command::SUCCESS;
            }

            $styledOutput->error('Error while updating service definition : '.$e->getMessage());

            return Command::FAILURE;
        }

        $styledOutput->success('Service definition updated');

        return Command::SUCCESS;
    }
}
