<?php

namespace XF\Cli\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableCell;
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class FileCheck extends Command
{
	protected function configure()
	{
		$this
			->setName('xf:file-check')
			->setDescription('Performs a file health check')
			->addOption(
				'addon',
				'a',
				InputOption::VALUE_REQUIRED,
				'Add-on to limit to checking (default: all)'
			);
	}

	protected function execute(InputInterface $input, OutputInterface $output)
	{
		$addOnInfo = [];

		$ds = DIRECTORY_SEPARATOR;
		$addOnId = $input->getOption('addon');
		if ($addOnId == 'XF')
		{
			$addOnInfo['XF'] = [
				'title' => 'XenForo',
				'hash' => \XF::getAddOnDirectory() . $ds . 'XF' . $ds . 'hashes.json'
			];
		}
		else if ($addOnId)
		{
			/** @var \XF\AddOn\AddOn $addOn */
			$addOn = \XF::app()->addOnManager()->getById($addOnId);
			if (!$addOn)
			{
				$output->writeln('<error>' . \XF::phrase('please_enter_valid_addon_id') . '</error>');
				return 1;
			}
			$addOnInfo[$addOnId] = [
				'title' => $addOn->title,
				'hash' => $addOn->getHashesPath()
			];
		}
		else
		{
			$addOns = \XF::app()->addOnManager()->getAllAddOns();
			foreach ($addOns AS $addOnId => $addOn)
			{
				if (!$addOn->isInstalled())
				{
					continue;
				}
				$addOnInfo[$addOnId] = [
					'title' => $addOn->title,
					'hash' => $addOn->getHashesPath()
				];
			}
			$addOnInfo['XF'] = [
				'title' => 'XenForo',
				'hash' => \XF::getAddOnDirectory() . $ds . 'XF' . $ds . 'hashes.json'
			];
		}

		$results = [
			'missing' => [],
			'inconsistent' => [],
			'total_missing' => 0,
			'total_inconsistent' => 0,
			'total_checked' => 0
		];

		$rootPrefix = \XF::getRootDirectory() . $ds;

		$hashesMissing = [];

		foreach ($addOnInfo AS $addOnId => $info)
		{
			if (!file_exists($info['hash']))
			{
				$hashesMissing[$addOnId] = $info;
				continue;
			}

			$json = json_decode(file_get_contents($info['hash']), true);
			foreach ((array)$json AS $info => $hash)
			{
				$path = $rootPrefix . $info;

				$results['total_checked']++;
				if (!file_exists($path))
				{
					$results['missing'][$addOnId][] = $info;
					$results['total_missing']++;
				}
				else if (\XF\Util\Hash::hashTextFile($path, 'sha256') !== $hash)
				{
					$results['inconsistent'][$addOnId][] = $info;
					$results['total_inconsistent']++;
				}
			}
		}

		if ($hashesMissing)
		{
			$skipMissingHashes = \XF::app()->config['development']['enabled'];

			$output->writeln('<error>' . \XF::phrase('following_add_ons_missing_necessary_files_for_health_checking') . '</error>');
			foreach ($hashesMissing AS $addOn)
			{
				$output->writeln("\t * $addOn[title]");
			}

			if ($skipMissingHashes)
			{
				$output->writeln(\XF::phrase('execution_has_been_allowed_to_continue')->render());
			}
			else
			{
				return 1;
			}
		}

		if (!$results['total_missing'] && !$results['total_inconsistent'])
		{
			if (!$hashesMissing)
			{
				$output->writeln('<info>' . \XF::phrase('file_health_check_okay', ['numFiles' => $results['total_checked']]) . '</info>');
			}

			return 0;
		}
		$table = new Table($output);

		foreach ($addOnInfo AS $addOnId => $info)
		{
			if (isset($results['missing'][$addOnId]) || isset($results['inconsistent'][$addOnId]))
			{
				$table->setHeaders([
					[new TableCell($info['title'], ['colspan' => 2])],
					['File path', 'Status']
				]);

				if (isset($results['inconsistent'][$addOnId]))
				{
					foreach ($results['inconsistent'][$addOnId] AS $path)
					{
						$table->addRow([$path, 'Inconsistent']);
					}

					if (isset($results['missing'][$addOnId]))
					{
						$table->addRow(new TableSeparator());
					}
				}
				if (isset($results['missing'][$addOnId]))
				{
					foreach ($results['missing'][$addOnId] AS $path)
					{
						$table->addRow([$path, 'Missing']);
					}
				}
			}
		}

		$output->writeln('<error>' . \XF::phrase('check_completed_on_x_files', ['total_checked' => $results['total_checked']]) . '</error>');

		$table->render();

		return 1;
	}
}