<?php

namespace StevenBuehner\sbChurchtoolsGrouphomepage\Controller;

use StevenBuehner\sbChurchtoolsGrouphomepage\Always\MyContainer;
use StevenBuehner\sbChurchtoolsGrouphomepage\Controller\AbstractController;
use StevenBuehner\sbChurchtoolsGrouphomepage\Helper\ArrayHelper;
use StevenBuehner\sbChurchtoolsGrouphomepage\Helper\iCalHelper;
use StevenBuehner\sbChurchtoolsGrouphomepage\Service\Exceptions\InvalidArgumentException;
use StevenBuehner\sbChurchtoolsGrouphomepage\Service\Models\Event;
use StevenBuehner\sbChurchtoolsGrouphomepage\Vendor\Symfony\Contracts\Cache\ItemInterface;

/**
 * The public-facing functionality of the plugin.
 *
 * @link       http://example.com
 * @since      1.0.0
 *
 * @package    sbChurchtoolsGrouphomepage
 */

/**
 * The public-facing functionality of the plugin.
 *
 * Defines the plugin name, version, and two examples hooks for how to
 * enqueue the public-facing stylesheet and JavaScript.
 *
 * @author     Steven Buehner <buehner@me.com>
 */
class GroupHomepageFrontendController extends AbstractController {

	const ICAL_ACTION = 'sb-churchtools-grouphomepage_events';

	function init(): void {

		$this->setUpHooks(
			FALSE,
			FALSE,
			FALSE,
			TRUE,
			FALSE,
			TRUE,
			TRUE
		);

		$this->domain = "sb-ct-blocks";

	}

	public function registerGutenbergBlocksAndCategories() {

		parent::registerGutenbergBlocksAndCategories();

		$this->registerBlockJson(__DIR__ . '/../../build/GroupHomepage', TRUE, TRUE);

	}

	public function registerRestRequests() {

		parent::registerRestRequests();

		register_rest_route('churchtools/grouphomepage/v1', '/get', [
			'methods'             => \WP_REST_Server::READABLE,
			'callback'            => [$this, 'action_get_ct_grouphomepage_json'],
			'args'                => array(
				'grouphomepage' => [
					'description'       => 'ChurchTools Grouphomepage URL',
					'type'              => 'string',
					'validate_callback' => '__return_true',
					'required'          => TRUE
				],
			),
			'permission_callback' => '__return_true',
		]);

	}


	public function render($props = [], $content = '') {

		$componentProps = [
			'props' => ArrayHelper::extractKeys($props, ['showsearchinput', 'listingButtons', 'view', 'labelOverview', 'labelDetails', 'labelDetailsAndRegister', 'labelLeader', 'labelRegister', 'labelContactLeader']),
			'class' => preg_replace('~/~', '-', reset($this->registeredBlocks)->name)
		];

		$response               = $this->action_get_ct_grouphomepage_json($props);
		$componentProps['data'] = $response['data'];

		return $this->modifyHtmlElement($content, $componentProps);

	}

	public function action_get_ct_grouphomepage_json($props) {

		if (!isset($props['grouphomepage']) || empty ($props['grouphomepage'])) {
			return ['success' => FALSE, 'message' => __('Missing Grouphomepage URL. Please configure first!', $this->domain)];
		}

		try {

			list($allGroups, $allEvents) = $this->getGroupsAndEventsFromUrl($props['grouphomepage']);

			return [
				'success' => TRUE,
				'data'    => [
					'json-list'     => wp_json_encode($allGroups),
					'json-events'   => wp_json_encode($allEvents),
					'json-base-url' => wp_json_encode('https://' . parse_url($props['grouphomepage'], PHP_URL_HOST)),
				]
			];

		} catch (\Exception $e) {
			return [
				'success' => FALSE,
				'error'   => $e->getMessage()
			];
		}
	}

	protected function getGroupsAndEventsFromUrl($groupHomepageUrl) {

		try {
			$allGroups   = $this->getGroupHomepageFromUrl($groupHomepageUrl)['groups'];
			$groupEvents = [];

			$pattern = '~\!\[\]\((?<url>([0-9]+|https?:\/\/[^\)]+churchcal)(.+))\)\s*($|\n)~';

			foreach ($allGroups as $index => $group) {
				$id               = (int)$group['id'];
				$groupEvents[$id] = [];

				if (isset($group['information']) && isset($group['information']['note'])) {
					$note = $group['information']['note'];

					if (preg_match_all($pattern, (string)$note, $match) > 0) {
						foreach ($match['url'] as $url) {
							$groupEvents[$id] = array_merge($groupEvents[$id], $this->parseCalendarEventsStringToEvents($url));
						}

						// Entferne Url in Grouphomepage Notiz
						$note                                     = str_replace($match[0], '', $note);
						$allGroups[$index]['information']['note'] = $note;
					}
				}

				// Entferne die überladenen Campus-Informationen
				if (isset($group['information']['campus'])) {
					$campus                                     = $group['information']['campus'];
					$allGroups[$index]['information']['campus'] = [
						'name'           => $campus['name'],
						'nameTranslated' => $campus['nameTranslated'],
					];
				}
			}

			return [$allGroups, $groupEvents];

		} catch (\Exception $e) {
			error_log(print_r($e, TRUE));

			return [[], []];
		}

	}

	/**
	 * @param $requestString
	 * @return Event[]
	 * @throws \Exception
	 */
	protected function parseCalendarEventsStringToEvents($requestString) {

		// $urlOnlyPattern = '(?<url>[^\$]+)';
		$allowedKeys = ['maxEvents', 'filterTitle', 'filterDesc', 'maxDate', 'removeDesc', 'removeBrackets'];
		$elements    = preg_split('~\$\$~', $requestString);
		$urlHasOrId  = array_shift($elements);
		$service     = MyContainer::getCtCalendarService();
		$properties  = [];

		foreach ($elements as $el) {
			if (!empty($el) && preg_match('~^(?<key>[^=]+)=(?<value>.+)$~', $el, $elMatch) === 1 && in_array($elMatch['key'], $allowedKeys)) {
				$properties[$elMatch['key']] = $elMatch['value'];
			}
		}

		$maxItems       = (isset($properties['maxEvents']) && is_numeric($properties['maxEvents'])) ? (int)$properties['maxEvents'] : 5;
		$titleRegExp    = (isset($properties['filterTitle']) && iCalHelper::isValidRegExp($properties['filterTitle'])) ? $properties['filterTitle'] : '';
		$descrRegExp    = (isset($properties['filterDesc']) && iCalHelper::isValidRegExp($properties['filterDesc'])) ? $properties['filterDesc'] : '';
		$maxDate        = (isset($properties['maxDate']) && iCalHelper::isValidRegExp($properties['maxDate'])) ? $properties['maxDate'] : NULL;
		$removeDesc     = isset($properties['removeDesc']);
		$removeBrackets = isset($properties['removeBrackets']);

		// Validate MaxDate > now
		if (!empty($maxDate)) {
			$now     = new \DateTime();
			$date    = new \DateTime($maxDate);
			$maxDate = ($date > $now) ? $date : NULL;
		}

		try {
			$events = $service->getFilteredEventsFromCalendar($urlHasOrId, $maxItems, $titleRegExp, $descrRegExp, $maxDate);
		} catch (InvalidArgumentException $e) {
			$events = [];
		}

		// Do some filter Operations
		$removeBracketsPattern = '~\s*\([^\)\(]+\)\s*~';
		foreach ($events as $e) {
			if ($removeDesc) {
				$e->clearDescription();
			}

			if ($removeBrackets) {
				$e->setTitle(preg_replace($removeBracketsPattern, '', $e->getTitle()));
				$e->setDescription(preg_replace($removeBracketsPattern, '', $e->getDescription()));
				$e->setLocation(preg_replace($removeBracketsPattern, '', $e->getLocation()));
			}
		}

		return $events;

	}

	protected function getGroupHomepageFromUrl($url) {

		// Verify Input - Check URL

		// i.e. https://teambb.church.tools/grouphomepage/gRpfHe9ZJ6NlKOSBVSjfix8Wq7PTRyEn
		if (preg_match('~^(?<base>https?:\/\/[^\/]+)\/grouphomepage\/(?<security>[a-zA-Z0-9]+)$~', $url, $match) !== 1) {
			throw new \Exception('Invalid Grouphomepage URL - Security Error');
		}
		$base     = $match['base'];
		$security = $match['security'];

		$config = MyContainer::getChurchToolsConfig();
		$host   = $config->getHost();
		$host   = preg_replace('~\/api\/?$~', '', $host); // Entferne das /api

		if ($base !== $host) {
			throw new \Exception('Host missmatch with settings in backend - Security Error');
		}

		// Json URL
		// i.e. https://teambb.church.tools/api/grouphomepages/gRpfHe9ZJ6NlKOSBVSjfix8Wq7PTRyEn

		$url          = "{$host}/api/grouphomepages/{$security}";
		$cacheAdapter = MyContainer::getCacheAdapter();
		$cacheKey     = md5($url);

		if (is_user_logged_in()) {
			$cacheAdapter->delete($cacheKey);
		}

		try {
			$data = $cacheAdapter->get($cacheKey, function (ItemInterface $item) use ($url) {
				$item->expiresAfter(60 * 15); // 15 Minuten
				$json = file_get_contents($url);
				$data = json_decode($json, TRUE);

				if (isset($data['data'])) {
					return $data['data'];
				} else {
					throw new \Exception('Malformed ChurchTools Response');
				}
			});
		} catch (\Exception $e) {
			throw new \Exception('Error parsing ChurchTools Server Response');
		}

		return $data;

	}


	protected function getPublicGroupDetails($securityHash, $groupId) {

		// Verify Input - Check URL
		$groupId = (int)$groupId;

		if (preg_match('~^[a-z0-9A-Z]+$~', $securityHash) !== 1) {
			throw new \Exception('Security Hash Missmatch');
		}


		// $url ...       return this.domain + '/api/publicgroups/' + this.groupId + '/' + this.grouphash;
		$config       = MyContainer::getChurchToolsConfig();
		$url          = $config->getHost() . "/publicgroups/{$groupId}/{$securityHash}";
		$cacheAdapter = MyContainer::getCacheAdapter();
		$cacheKey     = md5($url);

		if (is_user_logged_in()) {
			$cacheAdapter->delete($cacheKey);
		}

		try {

			$data = $cacheAdapter->get($cacheKey, function (ItemInterface $item) use ($url) {
				$item->expiresAfter(60 * 3); // 3 Minuten
				$json = file_get_contents($url);
				$data = json_decode($json, TRUE);

				if (isset($data['data'])) {
					return $data['data'];
				} else {
					throw new \Exception('Malformed ChurchTools Response');
				}
			});
		} catch (\Exception $e) {
			throw new \Exception('Error parsing ChurchTools Server Response');
		}

		return $data;

	}


}
