<?php

namespace XF\Cli\Command\Designer;

use League\Flysystem\FilesystemException;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use XF\Cli\Command\AbstractCommand;
use XF\Cli\Command\StyleArchiveTrait;
use XF\Util\File;

class Enable extends AbstractCommand
{
	use RequiresDesignerModeTrait;
	use StyleArchiveTrait;

	protected function configure()
	{
		$this
			->setName('xf-designer:enable')
			->setDescription('Enables designer mode on the specified style')
			->addArgument(
				'style-id',
				InputArgument::REQUIRED,
				'Style ID'
			)
			->addArgument(
				'designer-mode',
				InputArgument::REQUIRED,
				'Designer mode ID'
			);
	}

	protected function execute(InputInterface $input, OutputInterface $output)
	{
		/** @var QuestionHelper $helper */
		$helper = $this->getHelper('question');

		$style = $this->getStyleByStyleIdInput($input, $output);

		if ($style->designer_mode)
		{
			$output->writeln(\XF::phrase('once_enabled_it_is_not_possible_to_change_designer_mode_id')->render());
			return 1;
		}

		$designerMode = $input->getArgument('designer-mode');
		$style->designer_mode = $designerMode;

		$dataUriAssets = [];
		foreach ($style->assets AS $k => $assetPath)
		{
			$dataUriRegex = '#^data://styles/\d+/#';
			if (preg_match($dataUriRegex, $assetPath))
			{
				$dataUriAssets[$k] = [$assetPath, preg_replace($dataUriRegex, '', $assetPath)];
			}
		}

		if ($dataUriAssets)
		{
			$output->writeln("");

			$question = new ConfirmationQuestion("<question>This style has assets within the data directory. These will be copied to their original location. Is this ok? (y/n)</question> ");
			if (!$helper->ask($input, $output, $question))
			{
				return 1;
			}

			$newAssetValues = $style->assets;

			foreach ($dataUriAssets AS $k => $asset)
			{
				$finalPath = \XF::getRootDirectory() . '/' . $asset[1];
				if (!File::isWritable($finalPath))
				{
					$output->writeln('<error>The following asset path was not writable: ' . $asset[1] . '</error>');
					return 1;
				}

				$newAssetValues[$k] = $asset[1];
			}

			$style->assets = $newAssetValues;
		}

		if (!$style->preSave())
		{
			$output->writeln($style->getErrors());
			return 1;
		}

		$style->save();

		$this->copyDataUriAssets($dataUriAssets);

		$designerModePath = \XF::app()->designerOutput()->getDesignerModePath($style->designer_mode);
		$printablePath = str_replace(\XF::getRootDirectory() . \XF::$DS, '', $designerModePath);

		if (file_exists($designerModePath))
		{
			$question = new ChoiceQuestion(
				"<question>The designer mode path '$printablePath' already exists. How should this be treated?</question>",
				[
					'dir' => 'Treat the directory as the master version. (Overwrite style from directory.)',
					'db' => 'Treat the database as the master version. (Overwrite directory from style.)',
					'' => 'Do nothing. (You will need to resolve this manually.)',
				]
			);

			$action = $helper->ask($input, $output, $question);
			switch ($action)
			{
				case 'dir':
					$this->runImport($designerMode, $output);
					break;

				case 'db':
					File::deleteDirectory($designerModePath);
					File::createDirectory($designerModePath, false);
					$this->runExport($designerMode, $output);
			}
		}
		else
		{
			File::createDirectory($designerModePath, false);
			$this->runExport($designerMode, $output);
		}

		$output->writeln(["", "Designer mode enabled for '$style->title' in path '$printablePath'", ""]);

		return 0;
	}

	protected function copyDataUriAssets(array $dataUriAssets)
	{
		foreach ($dataUriAssets AS $asset)
		{
			$fs = \XF::fs();
			$dataUriPath = $asset[0];
			$finalAssetPath = \XF::getRootDirectory() . '/' . $asset[1];

			try
			{
				$metadata = $fs->getMetadata($dataUriPath);
			}
			catch (FilesystemException $e)
			{
				$metadata = false;
			}

			if (!$metadata)
			{
				continue;
			}

			if ($metadata['type'] == 'dir')
			{
				$contents = $fs->listContents($dataUriPath, true);

				foreach ($contents AS $file)
				{
					if ($file['type'] == 'dir')
					{
						continue;
					}

					$abstractedPath = 'data://' . $file['path'];

					$filePath = File::copyAbstractedPathToTempFile($abstractedPath);
					$stdPath = $this->stripDataStylesPathPrefix($abstractedPath);
					File::copyFile($filePath, $finalAssetPath . '/' . $stdPath, false);
				}
			}
			else
			{
				$filePath = File::copyAbstractedPathToTempFile($dataUriPath);
				$stdPath = $this->stripDataStylesPathPrefix($dataUriPath);
				File::copyFile($filePath, $finalAssetPath . '/' . $stdPath, false);
			}
		}
	}

	protected function stripDataStylesPathPrefix(string $abstractedPath): string
	{
		return preg_replace('#^data://styles/\d+/#i', '', $abstractedPath);
	}
}
