<?php

namespace App\Controller\Helper;

use App\Tool\Utils;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Templating\EngineInterface;
use Twig\Environment;

class AjaxResponseBuilder
{
	/** @var array */
	protected $snippets = [];
	/** @var RequestStack */
	protected $request;
	/** @var EngineInterface */
	protected $templating;
	/** @var Environment */
	protected $twig;

	/**
	 * @param Request         $request
	 * @param EngineInterface $templating
	 * @param Environment       $twig
	 */
	public function __construct(RequestStack $requestStack, EngineInterface $templating, Environment $twig)
	{
		$this->request = $requestStack->getCurrentRequest();
		$this->templating = $templating;
		$this->twig = $twig;

		$this->clearSnippets();
	}

	/**
	 * @return $this
	 */
	public function addFlashMessages()
	{
		return $this->addElement('#flash-messages', 'snippet/flashMessages.html.twig');
	}

	/**
	 * @param string $selector
	 * @param string $templateVariables
	 * @param string $body
	 * @param bool   $rendered
	 * @param bool   $append
	 *
	 * @return $this
	 */
	public function addElement($selector, $body, $templateVariables = [], $rendered = false, $append = false)
	{
		$this->snippets[$selector] = [
			'type' => ($append) ? 'element-append' : 'element',
			'templateVariables' => $templateVariables,
			(($rendered) ? 'body' : 'render') => $body,
		];

		return $this;
	}

	/**
	 * @param string $body
	 * @param string $templateVariables
	 * @param bool   $rendered
	 *
	 * @return $this
	 */
	public function addPopup($body, $templateVariables = [], $rendered = false)
	{
		$this->snippets['popup'] = [
			'type' => 'popup',
			'templateVariables' => $templateVariables,
			(($rendered) ? 'body' : 'render') => $body,
		];

		return $this;
	}

	/**
	 * @return $this
	 */
	public function closePopup()
	{
		$this->snippets['popup-close'] = ['type' => 'popup-close'];

		return $this;
	}

	/**
	 * @param string $selector
	 * @param string $body
	 *
	 * @return $this
	 */
	public function removeElement($selector, $body)
	{
		$this->snippets[$selector] = ['type' => 'remove', 'body' => $body];

		return $this;
	}

	/**
	 * @param string $selector
	 * @param string $body
	 *
	 * @return $this
	 */
	public function hideElement($selector, $body)
	{
		$this->snippets[$selector] = ['type' => 'hide', 'body' => $body];

		return $this;
	}

	/**
	 * @param string $selector
	 * @param string $body
	 *
	 * @return $this
	 */
	public function showElement($selector, $body)
	{
		$this->snippets[$selector] = ['type' => 'show', 'body' => $body];

		return $this;
	}

	/**
	 * @param string $url
	 * @param bool   $ajax
	 *
	 * @return $this
	 */
	public function addRedirect($url, $ajax = false)
	{
		if (!isset($this->snippets[$url])) {
			$this->snippets[$url] = [
				'type' => ($ajax) ? 'redirect-ajax' : 'redirect',
				'body' => $url,
			];
		}

		return $this;
	}

	/**
	 * @param string $script
	 *
	 * @return $this
	 */
	public function addEval($script)
	{
		if (!isset($this->snippets['eval'])) {
			$this->snippets['eval'] = ['type' => 'eval', 'body' => ''];
		}
		$this->snippets['eval']['body'] .= $script;

		return $this;
	}

	/**
	 * @param string $key
	 *
	 * @return $this
	 */
	public function removeSnippet($key)
	{
		unset($this->snippets[$key]);

		return $this;
	}

	/**
	 * @return $this
	 */
	public function clearSnippets()
	{
		$this->snippets = [];

		return $this;
	}

	/**
	 * @return RedirectResponse|JsonResponse
	 */
	public function getResponse()
	{
		if (!$this->request->isXmlHttpRequest()) {
			return new RedirectResponse(Utils::docUrl('/', $this->twig->getGlobals()['language']));
		} else {
			return new JsonResponse($this->buildResponse());
		}
	}

	/**
	 * @return array
	 */
	private function buildResponse()
	{
		$response = ['status' => 'success', 'snippets' => []];
		foreach ($this->snippets as $selector => $snippet) {
			$body = true;
			switch ($snippet['type']) {
				case 'element': case 'element-append': case 'remove': case 'hide':
				case 'show': case 'popup': case 'popup-close':
					if (isset($snippet['body'])) {
						$body = $snippet['body'];
					} elseif (isset($snippet['render'])) {
						$templateVariables = isset($snippet['templateVariables']) ?
							array_merge($this->twig->getGlobals(), $snippet['templateVariables']) :
							$this->twig->getGlobals();
						$body = $this->templating->render($snippet['render'], $templateVariables);
					}
					break;
				case 'redirect': case 'redirect-ajax': case 'eval':
					$body = $snippet['body'];
					break;
			}

			if ($selector) {
				$response['snippets'][$selector] = [
					'type' => $snippet['type'], 'body' => $body,
				];
			}
		}

		return $response;
	}
}
