<?php

/**
 * @package SP Page Builder
 * @author JoomShaper http://www.joomshaper.com
 * @copyright Copyright (c) 2010 - 2025 JoomShaper
 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 or later
 */

use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Router\Route;
use JoomShaper\SPPageBuilder\DynamicContent\Site\CollectionHelper;

/** No direct access. */
defined('_JEXEC') or die('Restricted access');

/**
 * The helper class for migrating from 3.x to 4.x
 *
 * @since	4.0.0
 */
final class AddonHelper
{
	public static $deviceList = ["xl", "lg", "md", "sm", "xs"];

	/**
	 * Generate the media query with respect to the device
	 *
	 * @param 	string 	$device
	 *
	 * @return 	string
	 * @since 	4.0.0
	 */
	public static function mediaQuery(string $device): string
	{
		$MEDIA_QUERY_MAP = [
			'xl' => '@media (max-width: 1399.98px) {',
			'lg' => '@media (max-width: 1199.98px) {',
			'md' => '@media (max-width: 991.98px) {',
			'sm' => '@media (max-width: 767.98px) {',
			'xs' => '@media (max-width: 575.98px) {',
		];

		return $MEDIA_QUERY_MAP[$device];
	}


	/**
	 * Initialize the device object with help of the device list.
	 *
	 * @param 	string 	$type	The type value. Accepted values are 'string', 'number', 'boolean'
	 *
	 * @return 	\stdClass
	 * @since 	4.0.0
	 */
	public static function initDeviceObject(string $type = 'string'): \stdClass
	{
		$DEVICE_MAP = ['string' => '', 'number' => 0, 'boolean' => false];
		$deviceObject = new \stdClass;

		foreach (self::$deviceList as $device)
		{
			$deviceObject->$device = $DEVICE_MAP[$type];
		}

		return $deviceObject;
	}

	/**
	 * Generate Multiple device wise object from settings object.
	 *
	 * @param 	\stdClass 	$settings	The settings object.
	 * @param 	string 		$prop		The settings property.
	 * @param 	string 		$cssProp	The CSS property.
	 * @param 	string 		$device		The device value.
	 * @param 	boolean 	$important	If the CSS property need to append the !important keyword.
	 * @param 	string 		$unit		The unit of the CSS property.
	 *
	 * @return 	\stdClass
	 * @since 	4.0.0
	 */
	public static function generateMultiDeviceObject($settings, $prop, $cssProp, $device, $important = false, $unit = "px")
	{
		$data = self::initDeviceObject();

		if (!isset($settings->$prop)) return $data;

		if (\is_string($cssProp))
		{
			$cssProp = [$cssProp];
		}

		$value = $settings->$prop;


		if (empty($unit))
		{
			$unit = '';
		}
		else
		{
			if (!empty($value->unit))
			{
				$unit = $value->unit;
			}
		}

		if (\is_object($value))
		{
			foreach ($data as $key => $value)
			{
				if (isset($settings->$prop->$key))
				{
					if (\is_object($settings->$prop->$key))
					{
						$_value = empty($settings->$prop->$key->value) ? '' : $settings->$prop->$key->value;

						if (preg_replace("@\s+@", '', $_value) !== '')
						{
							$_unit =  $settings->$prop->$key->unit;

							foreach ($cssProp as $css)
							{
								$data->$key = strpos($css, '%s') !== false
									? \sprintf($css, $_value)
									: $css . ': ' . ($_value ?? '');
								$data->$key .= $_unit ?? '';
								$data->$key .= $important ? ' !important;' : ';';
							}
						}
					}
					else
					{
						if (preg_replace("@\s+@", '', $settings->$prop->$key) !== '')
						{
							foreach ($cssProp as $css)
							{
								$data->$key .= strpos($css, '%s') !== false
									? \sprintf($css, $settings->$prop->$key)
									: $css . ': ' . ($settings->$prop->$key ?? '');

								$data->$key .= $unit ?? '';
								$data->$key .= $important ? ' !important;' : ';';
							}
						}
					}
				}
			}
		}
		else
		{
			if (isset($settings->$prop))
			{
				if (preg_replace("@\s+@", '', $settings->$prop) !== '')
				{
					foreach ($cssProp as $css)
					{
						$data->$device .= strpos($css, '%s') !== false
							? \sprintf($css, $settings->$prop)
							: $css . ': ' . ($settings->$prop ?? '');

						$data->$device .= $unit;
						$data->$device .= $important ? ' !important;' : ';';
					}
				}
			}
		}

		return $data;
	}

	/**
	 * Generate Spacing object from settings object.
	 *
	 * @param 	\stdClass 	$settings	The settings object.
	 * @param 	string 		$type		The spacing type, i.e. padding or margin
	 * @param 	string 		$device		The device.
	 *
	 * @return 	\stdClass
	 * @since 	4.0.0
	 */
	public static function generateSpacingObject($settings, $prop, $cssProp, $device)
	{
		$object = self::initDeviceObject();
		$positions = ["top", "right", "bottom", "left"];
		$borderRadiusPositions = ["top-left", "top-right", "bottom-right", "bottom-left"];

		if (\is_string($cssProp))
		{
			$cssProp = [$cssProp];
		}

		$value = $settings->$prop;

		if (!isset($settings->$prop) || empty($settings->$prop)) return $object;

		if (\is_object($settings->$prop))
		{
			foreach ($object as $key => $_)
			{
				if (isset($settings->$prop->$key))
				{
					$value = (string) $settings->$prop->$key;
					$value = \preg_replace("@\s+@", ' ', $value);
					$valueArray = \ctype_space((string)$value) || $value === '' ? [] : explode(' ', $value);

					if (!empty($valueArray))
					{
						$object->$key = implode(
							"\r\n",
							array_map(function ($x, $i) use ($cssProp, $positions, $borderRadiusPositions)
							{
								$str = '';

								foreach ($cssProp as $attr)
								{
									$x = strpos($x, '%s') !== false ? \sprintf($attr, $x) : $x;

									if ($attr === "border-radius")
									{
										$attr = explode('-', $attr);

										$str .= isset($x) && !\ctype_space((string)$x) && !empty((string) $x) ? $attr[0] . '-' . $borderRadiusPositions[$i] . '-' . $attr[1] . ': ' . $x . ';' : '';
									}
									else
									{
										$str .= isset($x) && !\ctype_space((string) $x) && !empty((string) $x) ? $attr . '-' . $positions[$i] . ': ' . $x . ';' : '';
									}
								}

								return $str;
							}, $valueArray, array_keys($valueArray))
						);
					}
				}
			}
		}
		else
		{
			$value = isset($settings->$prop) ? (string) $settings->$prop : '';
			$value = \preg_replace("@\s+@", ' ', $value);
			$valueArray = \ctype_space((string)$value) || $value === '' ? [] : explode(' ', $value);

			$object->$device = implode(
				"\r\n",
				array_map(function ($x, $i) use ($cssProp, $positions, $borderRadiusPositions)
				{
					$str = '';

					foreach ($cssProp as $attr)
					{
						$x = strpos($x, '%s') !== false ? \sprintf($attr, $x) : $x;

						if ($attr === "border-radius")
						{
							$attr = explode('-', $attr);
							$str .= isset($x) ? $attr[0] . '-' . $borderRadiusPositions[$i] . '-' . $attr[1] . ': ' . $x . ';' : '';
						}
						else
						{
							$str .= isset($x) ? $attr . '-' . $positions[$i] . ': ' . $x . ';' : '';
						}
					}

					return $str;
				}, $valueArray, array_keys($valueArray))
			);
		}

		return $object;
	}

	/**
	 * Get dynamic content link.
	 *
	 * @param  \stdClass 	$settings	The settings object.
	 * @param  string 		$prop		The settings property.
	 * 
	 * @return array
	 * @since  4.0.0
	 */
	private static function getDynamicContentLink($settings, $prop) {
		$link = $settings->$prop;
		$linkOptions = [
			'url' => CollectionHelper::createDynamicContentLink(
				$link, $settings->dynamic_item
			),
			'target' => $link->new_tab ? '_blank' : null,
			'nofollow' => $link->nofollow ?? null,
			'noreferrer' => $link->noreferrer ?? null,
			'noopener' => $link->noopener ?? null,
		];
		$linkAttributes = CollectionHelper::generateLinkAttributes($linkOptions);

		if (empty($linkAttributes['has_link'])) {
			return ['', ''];
		}

		$href = $linkAttributes['href'] ?? '';
		$target = $linkAttributes['target'] ?? '';
		$rel = $linkAttributes['rel'] ?? '';

		return [$href, $target . $rel];
	}

	/**
	 * Convert new link form old link.
	 *
	 * @param  \stdClass 	$settings	The settings object.
	 * @param  string 		$prop		The settings property.	
	 * @param  array  		$fallback	The fallback settings property.
	 * 
	 * @return array
	 * @since  4.0.0
	 */
	public static function parseLink($settings, $prop, $fallback = [])
	{
		if (isset($settings->dynamic_item)) {
			return static::getDynamicContentLink($settings, $prop);
		}

		$hasFallback = !empty($fallback) && !isset($settings->$prop);

		if ($hasFallback)
		{
			$url = array_key_exists('url', $fallback) ? $fallback['url'] : '';
			$newTab = array_key_exists('new_tab', $fallback) ? $fallback['new_tab'] : '';
			$nofollow = array_key_exists('nofollow', $fallback) ? $fallback['nofollow'] : '';
			$noreferrer = array_key_exists('noreferrer', $fallback) ? $fallback['noreferrer'] : '';
			$noopener = array_key_exists('noopener', $fallback) ? $fallback['noopener'] : '';

			$settings->$prop = new \stdClass;
			$settings->$prop->url = isset($settings->$url) && \is_string($settings->$url) ? $settings->$url : '';
			$settings->$prop->new_tab = $settings->$newTab ?? 0;
			$settings->$prop->nofollow = $settings->$nofollow ?? 0;
			$settings->$prop->noreferrer = $settings->$noreferrer ?? 0;
			$settings->$prop->noopener = $settings->$noopener ?? 0;
			$settings->$prop->type = 'url';
		}

		if (empty($settings->$prop)) return ['', ''];

		$link = $settings->$prop;

		if (\is_string($link))
		{
			return [$link, ''];
		}

		$url 	= '';
		$target = '';
		$rel 	= '';

		if (!empty($link->type))
		{
			switch ($link->type)
			{
				case 'menu':
					!empty($link->menu) ? $url = Route::_($link->menu) : $url = '';
					break;
				case 'page':
					!empty($link->page) ? $url = Uri::root(true) . '/index.php?option=com_sppagebuilder&view=page&id=' . $link->page : $url = '';
					break;
				case 'url':
					$url = $link->url;
					break;
				default:
					$url = '';
					$target = '';
					break;
			}
		}

		if (!empty($link->new_tab))
		{
			$target .= 'target="_blank"';
		}

		if (!empty($link->nofollow))
		{
			$rel 	 = "nofollow";
		}

		if (!empty($link->noreferrer))
		{
			$rel .= " noreferrer";
		}

		if (!empty($link->noopener))
		{
			$rel .= " noopener";
		}

		$target .= !empty($rel) ?  ' rel="' . trim($rel) . '"' : '';
		return [$url, $target];
	}
}
