<?php

namespace XF\Cli\Command;

use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class AddOnSubAction extends AbstractCommand
{
	use AddOnActionTrait;
	use JobRunnerTrait;

	protected function configure()
	{
		$this
			->setName('xf:addon-sub-action')
			->setDescription('Runs a add-on sub-action in a separate process. Do not run directly!')
			->setHidden(true)
			->addArgument(
				'id',
				InputArgument::REQUIRED,
				'Add-On ID'
			)
			->addArgument(
				'action',
				InputArgument::REQUIRED
			)
			->addOption(
				'k',
				null,
				InputOption::VALUE_REQUIRED,
				'Confirmation key (to allow this to be run)'
			);
	}

	protected function execute(InputInterface $input, OutputInterface $output)
	{
		$id = $input->getArgument('id');
		$action = $input->getArgument('action');

		$expectedKey = $this->getSubActionKey($id, $action);
		if ($expectedKey !== $input->getOption('k'))
		{
			$output->writeln("<error>Invalid sub-action confirmation key. Run from parent command.</error>");
			return 1;
		}

		$addOnManager = \XF::app()->addOnManager();
		$addOn = $addOnManager->getById($id);
		if (!$addOn)
		{
			$output->writeln("<error>No add-on with ID '$id' could be found.</error>");
			return 1;
		}

		// make sure any errors get logged here
		\XF::app()->error()->setIgnorePendingUpgrade(true);

		try
		{
			switch ($action)
			{
				case 'import':
					$this->importAddOnData($input, $output, $addOn);
					break;

				case 'install':
					$this->performAddOnAction($input, $output, $addOn, \XF::phrase('installing'), 'install');
					break;

				case 'post-install':
					$stateChanges = [];
					$addOn->postInstall($stateChanges);
					break;

				case 'upgrade':
					$this->performAddOnAction($input, $output, $addOn, \XF::phrase('upgrading'), 'upgrade');
					break;

				case 'post-upgrade':
					$stateChanges = [];
					$addOn->postUpgrade($stateChanges);
					break;

				case 'uninstall':
					$this->performAddOnAction($input, $output, $addOn, \XF::phrase('uninstalling'), 'uninstall');
					break;

				case 'uninstall-data':
					$installed = $addOn->getInstalledAddOn();
					if ($installed)
					{
						$installed->delete();
					}
					break;

				case 'post-uninstall':
					$addOn->postUninstall();
					break;

				case 'post-rebuild':
					$addOn->postRebuild();
					break;

				case 'active-change':
					\XF::app()->addOnDataManager()->triggerRebuildActiveChange($addOn->getInstalledAddOn());
					break;

				default:
					throw new \InvalidArgumentException("Unknown action '$action'");
			}
		}
		catch (\Exception $e)
		{
			// taking this approach so that we don't get double logging
			\XF::logException($e, true, '', true);

			$output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
			$this->getApplication()->renderThrowable($e, $output);

			return 222;
		}
		catch (\Throwable $e)
		{
			// taking this approach so that we don't get double logging
			\XF::logException($e, true, '', true);

			$e = new \ErrorException($e);

			$output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
			$this->getApplication()->renderThrowable($e, $output);

			return 222;
		}

		return 0;
	}
}
