<?php

namespace SGalinski\SgNews\ViewHelpers;

use SGalinski\SgNews\Domain\Repository\CategoryRepository;
use SGalinski\SgNews\Domain\Repository\NewsRepository;
use SGalinski\SgNews\Domain\Service\NewsService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;

/**
 * Renders related news based on the current news
 */
class RelatedViewHelper extends AbstractViewHelper {
	use CompileWithRenderStatic;

	/**
	 * @var bool
	 */
	protected $escapeOutput = FALSE;

	/**
	 * Initialize the view helper arguments
	 */
	public function initializeArguments() {
		$this->registerArgument(
			'news',
			'SGalinski\SgNews\Domain\Model\News',
			'The news record from which to find related news',
			TRUE
		);
		$this->registerArgument(
			'limit',
			'int',
			'Limit the amount of related news to display',
			FALSE,
			5
		);
		$this->registerArgument(
			'as',
			'string',
			'The name of the iteration variable',
			TRUE
		);
		$this->registerArgument(
			'iteration',
			'string',
			'The name of the variable to store iteration information (index, cycle, isFirst, isLast, isEven, isOdd)'
		);
		$this->registerArgument(
			'relatedNews',
			ObjectStorage::class,
			'An optional list of related news to take instead of finding some via the news repository',
			FALSE,
			NULL
		);
	}

	/**
	 * It works like the for-ViewHelper by running through the child content and adding the related news records to it
	 *
	 * @param array $arguments
	 * @param \Closure $renderChildrenClosure
	 * @param RenderingContextInterface $renderingContext
	 * @return string
	 * @throws \Doctrine\DBAL\Driver\Exception
	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
	 */
	public static function renderStatic(
		array $arguments,
		\Closure $renderChildrenClosure,
		RenderingContextInterface $renderingContext
	) {
		$newsService = GeneralUtility::makeInstance(NewsService::class);
		$categoryRepository = GeneralUtility::makeInstance(CategoryRepository::class);
		$templateVariableContainer = $renderingContext->getVariableProvider();
		$news = $arguments['news'];
		$newsRepository = GeneralUtility::makeInstance(NewsRepository::class);
		if ($arguments['relatedNews']) {
			$related = $arguments['relatedNews'];
		} else {
			$related = $newsRepository->findRelated($news, (int) $arguments['limit']);
		}

		if (isset($arguments['iteration'])) {
			$iterationData = [
				'index' => 0,
				'cycle' => 1,
				'total' => $related->count()
			];
		}

		$output = '';
		$categories = [];
		foreach ($related as $relatedNews) {
			if (!isset($categories[$relatedNews->getPid()])) {
				$categories[$relatedNews->getPid()] = $categoryRepository->findByUid($relatedNews->getPid());
			}

			$newsMetaData = $newsService->getMetaDataForNews($relatedNews, $categories[$relatedNews->getPid()]);
			$templateVariableContainer->add($arguments['as'], $newsMetaData);
			if (isset($iterationData)) {
				$iterationData['isFirst'] = $iterationData['cycle'] === 1;
				$iterationData['isLast'] = $iterationData['cycle'] === $iterationData['total'];
				$iterationData['isEven'] = $iterationData['cycle'] % 2 === 0;
				$iterationData['isOdd'] = !$iterationData['isEven'];
				$templateVariableContainer->add($arguments['iteration'], $iterationData);
				$iterationData['index']++;
				$iterationData['cycle']++;
			}

			$output .= $renderChildrenClosure();
			$templateVariableContainer->remove($arguments['as']);
			if (isset($arguments['iteration'])) {
				$templateVariableContainer->remove($arguments['iteration']);
			}
		}

		return $output;
	}
}