<?php

namespace StevenBuehner\sbChurchtoolsGrouphomepage\Controller;


/**
 * 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>
 */
abstract class AbstractController {

	/** @var \WP_Block_Type[] $registeredBlocks */
	protected array $registeredBlocks = [];

	/**
	 * Initialize the class and set its properties.
	 *
	 * @param string $domain The name of the plugin.
	 * @param string $version The version of this plugin.
	 * @param bool $debugMode
	 * @since    1.0.0
	 */
	public function __construct(protected string $domain, protected string $version, protected bool $debugMode) {
		$this->init();
	}

	abstract protected function init(): void;

	protected function frontendBaseUrl(): string {
		$srcBase = ($this->debugMode === TRUE) ? 'http://localhost:8080/' : plugin_dir_url((__DIR__)) . 'frontend/';
		return $srcBase;
	}

	protected function setUpHooks($useShortcodes = FALSE, $useBackendAssets = FALSE, $useFrontendAssets = TRUE, $useBlockAssets = FALSE, $useAjax = FALSE, $useRest = FALSE, $useLanguageSupport = FALSE): void {


		add_action('init', [$this, 'fireInitHooks']);

		if ($useShortcodes) {
			// https://developer.wordpress.org/reference/functions/add_shortcode/
			// Laut Doku eigentlich im "init" Hook - aber wp_loaded wird nur im Frontend geladen => performanter
			add_action('wp_loaded', [$this, 'registerShortcodes']);
		}

		if ($useBackendAssets) {
			add_action('admin_enqueue_scripts', [$this, 'enqueueBackendScripts']);
			add_action('admin_enqueue_scripts', [$this, 'enqueueBackendStyles']);
		}

		if ($useFrontendAssets) {
			// https://developer.wordpress.org/reference/hooks/wp_enqueue_scripts/
			add_action('wp_enqueue_scripts', [$this, 'enqueueFrontendScripts']);
			add_action('wp_enqueue_style', [$this, 'enqueueFrontendStyles']);
		}

		if ($useBlockAssets && function_exists('register_block_type')) {

			add_action('init', [$this, 'registerGutenbergBlocksAndCategories']);
			add_action('enqueue_block_assets', [$this, 'enqueuePublicBlockAssets']);

		}

		if ($useAjax) {
			add_action('init', [$this, 'registerAjaxRequests']);
		}

		if ($useRest) {
			add_action('rest_api_init', [$this, 'registerRestRequests']);
		}

		if ($useLanguageSupport) {
			add_action('init', [$this, 'registerLanguageSupport']);
		}

	}

	public function fireInitHooks(): void {
		$this->registerScripts();
		$this->registerStyles();
	}

	/**
	 * Hier werden alle (!) JS-Dateien registriert - egal ob sie für Blocks, Frontend oder Backend verwendet werden
	 */
	public function registerScripts(): void {

		wp_register_script('sb-churchtools-node_vendors', $this->frontendBaseUrl() . 'js/node_vendors.js', [], $this->version, FALSE);

		/*
		 $srcBase = ($this->debugMode === TRUE) ? 'http://localhost:8080/' : plugin_dir_url(__FILE__) . '';

		wp_register_script(
			'my-testscript-editor',
			$srcBase . 'js/test-editor.js',
			['wp-blocks', 'wp-element', 'my-testscript'],
			$this->version
		);

		wp_register_script(
			'my-testscript',
			$srcBase . 'js/test-public.js',
			[],
			$this->version
		);
		*/

	}

	/**
	 * Hier werden alle (!) CSS-Dateien registriert - egal ob sie für Blocks, Frontend oder Backend verwendet werden
	 */
	public function registerStyles() {

		//Vendor
		wp_register_style('sb-churchtools-node_vendors', $this->frontendBaseUrl() . 'css/node_vendors.css', [], $this->version, FALSE);

		/*
        $srcBase = ($this->debugMode === TRUE) ? 'http://localhost:8080/' : plugin_dir_url(__FILE__) . '';

		wp_register_style(
			'my-teststyle-editor',
			$srcBase . 'css/test-editor.css',
			['my-teststyle'],
			$this->version
		);

		wp_register_style(
			'my-teststyle',
			$srcBase . 'css/test-public.css',
			[],
			$this->version
		);

		 */
	}


	public function enqueueFrontendScripts() {
		/*
		wp_enqueue_script(
			'my-testscript',
			plugins_url('js/test-editor.js', __FILE__),
			[],
			$this->version
		);
		*/
	}

	public function enqueueFrontendStyles() {

	}

	public function enqueueBackendScripts() {
		/*
		wp_enqueue_script(
			'my-testscript',
			plugins_url('js/test-editor.js', __FILE__),
			[],
			$this->version
		);
		*/
	}

	public function enqueueBackendStyles() {

	}

	/**
	 * Enqueue the JavaScript & Styles for the public-facing side of the site.
	 *
	 * @since    1.0.0
	 */
	public function enqueuePublicBlockAssets() {

		/*
		// Only load Javascript when block is used
		// Im Editor werden die Dateien trotzdem immer geladen, weil sie als Abhängigkeit definiert sind :-)
		if (has_block('sb-churchtools/grouphomepage')) {
			wp_enqueue_script('sb-churchtools-grouphomepage-frontend');
			wp_enqueue_style('sb-churchtools-grouphomepage-frontend');
		}
		*/

	}


	public function registerShortcodes() {
		// add_shortcode('documents_search', [$this, 'renderDocumentSearchForm']);w
	}

	public function registerGutenbergBlocksAndCategories() {

		add_filter('block_categories_all', function ($block_categories, $post) {

			$alreadyRegistered = FALSE;
			foreach ($block_categories as $c) {
				if ($c['slug'] === 'churchtools-blocks') {
					$alreadyRegistered = TRUE;
					break;
				}
			}

			if ($alreadyRegistered === FALSE) {
				$block_categories = array_merge(
					$block_categories,
					[[
						 'slug'  => 'churchtools-blocks',
						 'title' => __('ChurchTools', $this->domain),
					 ]]
				);
			}

			return $block_categories;
		}, 10, 2);

		/*
		add_filter('block_categories_all', function ($block_categories, $post) {
			return array_merge(
				$block_categories,
				array(
					array(
						'slug'  => 'churchtools-blocks',
						'title' => __('ChurchTools', $this->domain),
					),
				)
			);
		}, 10, 2);

		 register_block_type('sb-churchtools-grouphomepage/example-01-basic-esnext',
			array(
				'title'         => 'Example: Basic (esnext)',
				'api_version'   => 2,
				'editor_script' => 'my-testscript-editor', // werden automatisch eingebunden, sobald der Editor zu sehen is
				'editor_style'  => $this->debugMode ? NULL : 'my-teststyle-editor', // wird autom. eingebunden, sobald der Editor da ist
				// 'script'        => null, //
				// 'style'         => null, // Nicht angeben => sind als Abhängigkeit vom editor-style definiert und werden nur dann geladen, wenn sie tatsächlich vorkommen
			));
		*/


	}

	protected function registerBlockJson(string $pathToBlockJsonFolder, bool $hasEditScriptTranslation = FALSE, bool $hasViewScriptTranslation = FALSE): \WP_Block_Type|false {

		$block = register_block_type($pathToBlockJsonFolder);

		if ($block) {
			$this->registeredBlocks[] = $block;

			if ($hasEditScriptTranslation === TRUE) {
				// Kommt zum Einsatz in wp-includes/l10n.php => load_script_textdomain:1250
				wp_set_script_translations($block->editor_script_handles[0], $this->domain, $pathToBlockJsonFolder);
			}

			if ($hasViewScriptTranslation === TRUE) {
				// Kommt zum Einsatz in wp-includes/l10n.php => load_script_textdomain:1250
				wp_set_script_translations($block->view_script_handles[0], $this->domain, $pathToBlockJsonFolder);

				// Die Frontend-Skripte auch im Backend laden (eigentlich unnötig, aber nur so werden auch die Überseztungsdateien des Frontend-Skriptes eingebunden)
				$registeredScript = wp_scripts()->registered[$block->editor_script_handles[0]];
				if ($registeredScript instanceof \_WP_Dependency) {
					$registeredScript->deps[] = $block->view_script_handles[0];
				}

			}

			// Bei allen Styles die Versionierung ändern (zum Neuladen)
			if (TRUE === $this->debugMode) {
				$styleHandles = array_merge($block->editor_style_handles, $block->view_style_handles, $block->style_handles);
				$version      = time();

				foreach ($styleHandles as $handle) {
					$registeredStyle = wp_styles()->registered[$handle];

					if ($registeredStyle instanceof \_WP_Dependency) {
						$registeredStyle->ver = $version;

						// $replaced             = preg_replace('~localhost\:8888~', 'localhost:8887', $registeredStyle->src);
						// $registeredStyle->src = $replaced;
					}

				}

				/*
				$scriptHandles = array_merge($block->editor_script_handles, $block->view_script_handles, $block->script_handles);
				foreach ($scriptHandles as $handle) {
					$registeredScript = wp_scripts()->registered[$handle];

					if ($registeredScript instanceof \_WP_Dependency) {
						$replaced              = preg_replace('~localhost\:8888~', 'localhost:8887', $registeredScript->src);
						$registeredScript->src = $replaced;
					}
				}
				*/

			}
		}

		return $block;

	}

	public function registerAjaxRequests() {
		// https://www.user-mind.de/ajax-richtig-in-wordpress-nutzen/
		// Langsame (offizielle) Variante ...
		// add_action('wp_ajax_nopriv_' . self::action_verify_mail, [$this, 'action_verify_mail']);
		// add_action('wp_ajax_' . self::action_verify_mail, [$this, 'action_verify_mail']);
	}

	public function registerRestRequests() {
		// https://www.user-mind.de/ajax-richtig-in-wordpress-nutzen/
	}


	public function registerLanguageSupport() {
		/*
		if (function_exists('wp_set_script_translations')) {
			wp_set_script_translations('sb-churchtools-grouphomepage-frontend', $this->domain, plugin_dir_path(dirname(__FILE__)) . '/languages');
		}
		*/
	}


	/**
	 * Die Funktion greift sich aus dem $htmlContent-String alle Attribute raus, bearbeitet sie nach und gibt das den htmlContent dann wieder zurück
	 * @param string $htmlContent
	 * @param array $addOrOverrideAttributes
	 * @param array $removeAttributes
	 * @param bool $transformToDataset
	 * @return string
	 */
	protected function modifyHtmlElement(string $htmlContent, array $addOrOverrideAttributes = [], array $removeAttributes = [], bool $transformToDataset = TRUE) {

		$attributes = [];

		// Ein regulärer Ausdruck, um das Tag und die Attribute zu extrahieren
		preg_match('~<(\w+)(.*?)>~', $htmlContent, $matches);
		$tag = $matches[1];

		// Überprüfe, ob Attribute gefunden wurden
		if (isset($matches[2])) {
			// Ein regulärer Ausdruck, um einzelne Attribute zu extrahieren
			preg_match_all('/(data-)?([a-zA-Z-_]+)\s?=\s?["\']([^"\']*)["\']/', $matches[2], $attrMatches, PREG_SET_ORDER);

			// Füge die gefundenen Attribute dem Array hinzu
			foreach ($attrMatches as $attr) {
				// Entferne die umgebenden Anführungszeichen vom Attributwert
				$attributes[$attr[2]] = trim($attr[3], '"\'');
			}
		}

		// Entferne Attribute, deren Schlüssel in $removeAttributes vorkommen
		foreach ($removeAttributes as $key) {
			unset($attributes[$key]);
		}

		// Merge die attribute class zusammen, wenn vorhanden
		if (!empty($attributes['class']) && !empty($addOrOverrideAttributes['class'])) {
			$class                            = trim($attributes['class']) . ' ' . trim($addOrOverrideAttributes['class']);
			$addOrOverrideAttributes['class'] = $class;
		}

		// Ersetze oder füge Attribute hinzu, deren Schlüssel in $addOrOverrideAttributes vorkommen
		foreach ($addOrOverrideAttributes as $key => $value) {
			$attributes[$key] = $value;
		}

		// Und alles wieder zusammensetzen
		$attrString = '';

		foreach ($attributes as $key => $value) {
			// Escape attribute values to prevent HTML injection

			if (is_array($value) || is_object($value)) {
				$value = json_encode($value);
			}

			// Key von CamelCase zu KebabCase - da sie in HTML immer als lowercase interpretiert werden
			// Bsp: "halloDuCooler" => "hallo-du-cooler"
			$key = $this->camelCaseToKebabCase($key);

			$escapedValue  = htmlspecialchars("$value", ENT_QUOTES, 'UTF-8');
			$datasetPrefix = $transformToDataset === TRUE && !in_array($key, ['class', 'id']) ? 'data-' : '';
			$attrString    .= sprintf(' %s%s="%s"', $datasetPrefix, $key, $escapedValue);
		}

		return sprintf('<%s%s></%s>', $tag, $attrString, $tag);

	}

	protected function camelCaseToKebabCase(string $input): string {
		// Find alle Großbuchstaben und füge davor einen Bindestrich ein, dann kleinschreiben
		$kebab = strtolower(preg_replace('/([a-z])([A-Z])/', '$1-$2', $input));
		return $kebab;
	}


}
