<?php declare(strict_types = 1);

namespace idoit\Module\SyneticsFlows\Automation\Action\PerformExecution;

use Exception;
use idoit\Module\SyneticsFlows\Automation\Action\ActionType\IdoitCommand\IdoitCommandConfiguration;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionInfo\CallIdoitCommandInfo;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionResult\CliErrorExecutionResult;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionResult\CliExecutionResult;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionResult\ErrorExecutionResult;
use idoit\Module\SyneticsFlows\Automation\Action\ExecutionResult\ExecutionResult;
use idoit\Module\SyneticsFlows\Automation\Execution;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;

class CallIdoitCommandExecution implements PerformExecution
{
    public function __construct(private IdoitCommandConfiguration $configuration)
    {
    }

    public function perform(Execution $execution): ExecutionResult
    {
        $info = $execution->getExecution();

        if (!($info instanceof CallIdoitCommandInfo)) {
            return new ErrorExecutionResult('Unsupported execution');
        }
        $command = clone $this->configuration->findCommand($info->getCommand());
        $config = $this->configuration->get($info->getCommand());

        if (!$command || !$config) {
            return new ErrorExecutionResult('Command is not found');
        }
        $input = $config->prepareInput($info->getParameters(), $command->getDefinition());
        $input->setInteractive(false);
        $output = new BufferedOutput(OutputInterface::VERBOSITY_NORMAL);

        try {
            $exitCode = $command->run($input, $output);
            if ($exitCode === 0) {
                return new CliExecutionResult($output->fetch());
            }
            return new CliErrorExecutionResult($exitCode, $output->fetch());
        } catch (Exception $e) {
            return new ErrorExecutionResult($e->getMessage());
        }
    }

    public function supports(Execution $execution): bool
    {
        return $execution->getExecution() instanceof CallIdoitCommandInfo;
    }
}
