<?php

declare (strict_types=1);
namespace Rector\Console;

use RectorPrefix202606\Composer\XdebugHandler\XdebugHandler;
use Override;
use Rector\Application\VersionResolver;
use Rector\ChangesReporting\Output\ConsoleOutputFormatter;
use Rector\Configuration\Option;
use Rector\Util\Reflection\PrivatesAccessor;
use RectorPrefix202606\Symfony\Component\Console\Application;
use RectorPrefix202606\Symfony\Component\Console\Command\Command;
use RectorPrefix202606\Symfony\Component\Console\Input\InputDefinition;
use RectorPrefix202606\Symfony\Component\Console\Input\InputInterface;
use RectorPrefix202606\Symfony\Component\Console\Input\InputOption;
use RectorPrefix202606\Symfony\Component\Console\Output\OutputInterface;
use RectorPrefix202606\Symfony\Component\Console\Style\SymfonyStyle;
use RectorPrefix202606\Webmozart\Assert\Assert;
final class ConsoleApplication extends Application
{
    /**
     * @readonly
     */
    private SymfonyStyle $symfonyStyle;
    /**
     * @var string
     */
    private const NAME = 'Rector';
    /**
     * @param Command[] $commands
     */
    public function __construct(array $commands, SymfonyStyle $symfonyStyle)
    {
        $this->symfonyStyle = $symfonyStyle;
        parent::__construct(self::NAME, VersionResolver::PACKAGE_VERSION);
        Assert::notEmpty($commands);
        Assert::allIsInstanceOf($commands, Command::class);
        $this->addCommands($commands);
        // run this command, if no command name is provided
        $this->setDefaultCommand('process');
    }
    #[Override]
    public function doRun(InputInterface $input, OutputInterface $output): int
    {
        $this->enableXdebug($input);
        $shouldFollowByNewline = \false;
        // skip in this case, since generate content must be clear from meta-info
        if ($this->shouldPrintMetaInformation($input)) {
            $output->writeln($this->getLongVersion());
            $shouldFollowByNewline = \true;
        }
        if ($shouldFollowByNewline) {
            $output->write(\PHP_EOL);
        }
        $commandName = $input->getFirstArgument();
        if ($commandName === null) {
            return parent::doRun($input, $output);
        }
        // if paths exist or if the command name is not the first argument but with --option, eg:
        // bin/rector src
        // bin/rector --only "RemovePhpVersionIdCheckRector"
        // file_exists() can check directory and file
        if (file_exists($commandName) || isset($_SERVER['argv'][1]) && $commandName !== $_SERVER['argv'][1] && $input->hasParameterOption($_SERVER['argv'][1])) {
            // prepend command name if implicit
            $privatesAccessor = new PrivatesAccessor();
            $tokens = $privatesAccessor->getPrivateProperty($input, 'tokens');
            $tokens = array_merge(['process'], $tokens);
            $privatesAccessor->setPrivateProperty($input, 'tokens', $tokens);
        } elseif (!$this->has($commandName)) {
            $this->symfonyStyle->error(sprintf('The following given path does not match any files or directories: %s%s', "\n\n - ", $commandName));
            return \Rector\Console\ExitCode::FAILURE;
        }
        return parent::doRun($input, $output);
    }
    #[Override]
    protected function getDefaultInputDefinition(): InputDefinition
    {
        $defaultInputDefinition = parent::getDefaultInputDefinition();
        $this->removeUnusedOptions($defaultInputDefinition);
        $this->addCustomOptions($defaultInputDefinition);
        return $defaultInputDefinition;
    }
    private function shouldPrintMetaInformation(InputInterface $input): bool
    {
        $hasNoArguments = $input->getFirstArgument() === null;
        if ($hasNoArguments) {
            return \false;
        }
        $hasVersionOption = $input->hasParameterOption('--version');
        if ($hasVersionOption) {
            return \false;
        }
        $outputFormat = $input->getParameterOption(['-o', '--output-format']);
        return $outputFormat === ConsoleOutputFormatter::NAME;
    }
    private function removeUnusedOptions(InputDefinition $inputDefinition): void
    {
        $options = $inputDefinition->getOptions();
        unset($options['quiet'], $options['verbose'], $options['no-interaction']);
        $inputDefinition->setOptions($options);
    }
    private function addCustomOptions(InputDefinition $inputDefinition): void
    {
        $inputDefinition->addOption(new InputOption(Option::CONFIG, 'c', InputOption::VALUE_REQUIRED, 'Path to config file'));
        $inputDefinition->addOption(new InputOption(Option::DEBUG, null, InputOption::VALUE_NONE, 'Enable debug verbosity'));
        $inputDefinition->addOption(new InputOption(Option::XDEBUG, null, InputOption::VALUE_NONE, 'Allow running xdebug'));
        $inputDefinition->addOption(new InputOption(Option::CLEAR_CACHE, null, InputOption::VALUE_NONE, 'Clear cache before starting the execution of the command'));
    }
    private function enableXdebug(InputInterface $input): void
    {
        $isXdebugAllowed = $input->hasParameterOption('--xdebug');
        if (!$isXdebugAllowed) {
            $xdebugHandler = new XdebugHandler('rector');
            $xdebugHandler->setPersistent();
            $xdebugHandler->check();
            unset($xdebugHandler);
        }
    }
}
