<?php

/**
EDITOR
 */
add_action('enqueue_block_editor_assets', 'dragblock_appearance_panel_editor_assets');
function dragblock_appearance_panel_editor_assets()
{
	$panel = 'appearance';
	dragblock_enqueue("dragblock-{$panel}-panel", "build/applications/editor-panel-{$panel}/client/index.js", array(DRAGBLOCK_EDITOR_INIT_SLUG));
	dragblock_enqueue("dragblock-{$panel}-panel", "build/applications/editor-panel-{$panel}/client/index.css");
}


/**
 * Documents
 * https://jasonyingling.me/enqueueing-scripts-and-styles-for-gutenberg-blocks/
 */
/**
 * Documents:
 * https://github.com/WordPress/gutenberg/issues/23223
 */

/**
 * Render custom css for any block that has inlineStyle attribute
 * $block = array(5) {
  ["blockName"]=> string(21) "dragblock/wrapper"
  ["attrs"]=> array(2) {}
  ["innerBlocks"]=>array(0) {}
  ["innerHTML"]=>string(113) ""
 */

/**
We decided to place parent css before children css
so children could override the parent css in some situations
ex: 
    uid-parent .sub {} could be overridden by uid-children.sub {} 
    if we place the children css after the parent css
 */
global $dragblock_css;
$dragblock_css = array();

global $dragblock_theme_json;
global $dragblock_default_json;
global $dragblock_user_json;

/**
Collect complied CSS styles
 * @var string $block_content the entire block html including itself's tag
 * @var array $parsed_block the block data saved in editor, ex: attributes, blockName...
 * @var WP_Block $block the block PHP object
 */
add_filter('render_block', 'dragblock_appearance_collect_css', 10, 2);
function dragblock_appearance_collect_css($block_content, $parsed_block)
{
	// var_dump('dragblock_appearance_collect_css()', $parsed_block);
	// $__DEBUG__ = (
	//     'core/avatar' === $parsed_block['blockName'] || 
	//     'core/comment-template' === $parsed_block['blockName'] || 
	//     strpos($parsed_block['blockName'], 'comment') !== false ||
	//     !empty($parsed_block['attrs']['className']) && strpos($parsed_block['attrs']['className'], 'comment') !== false
	// );    
	// if (!empty($__DEBUG__)) {

	//     !empty($parsed_block['attrs']['className']) && var_dump('.'.$parsed_block['attrs']['className']);
	//     empty($parsed_block['attrs']['className']) && var_dump($parsed_block['blockName']);
	//     // !empty($parsed_block['attrs']['dragBlockStyles']) && var_dump(json_encode($parsed_block['attrs']['dragBlockStyles'], true));                
	// }
	// the null block has the same attributes as its original block but does not render
	if (
		'core/null' === $parsed_block['blockName'] ||
		empty($parsed_block['attrs']['dragBlockClientId'])
	) {
		return $block_content;
	}

	/**    
	 * We have to override some core selectors because WP have inline 
	 * core CSS that override our uid selector
	 * Ex: .wp-block-post-template will override .uidx
	 * even when  .uidx stays under the .wp-block-post-template
	 */
	// if ($parsed_block['blockName'] === 'core/post-template') {
	//     $uid_selector = '.wp-block-post-template' . $uid_selector;
	// }



	/**     
	 * We added $parsed_block['blockName'] as a prefix because some block like core/post-template
	 * will have a clone as core/null which have the same attribute but will not be rendered
	 */
	// $uid_key = $parsed_block['blockName'] . $parsed_block['attrs']['dragBlockClientId'];
	$uid_key = dragblock_uid_key($parsed_block);
	global $dragblock_css;
	// a block's css cannot be rendered twice
	// this happens for templates blocks such as core/comment-template
	if (!empty($dragblock_css[$uid_key])) {
		return $block_content;
	}

	$css = '';
	global $dragblock_uids;
	if (!empty($parsed_block['attrs']['dragBlockCSS'])) {
		if (!empty($dragblock_uids[$uid_key])) {
			$uid_selector = '.' . $dragblock_uids[$uid_key];
			$css =
				str_replace(
					'[data-dragblock-client-id="' . $parsed_block['attrs']['dragBlockClientId'] . '"]',
					$uid_selector,
					$parsed_block['attrs']['dragBlockCSS']
				);
		}
	}


	/**
    even when the css is empty and this has no uid, we still need to carry the children css 
	 */
	// rearrange the css order, so the children css will be rendered after the parent css
	if (!empty($parsed_block['innerBlocks'])) {
		foreach ($parsed_block['innerBlocks'] as $inner_block) {
			if (empty($inner_block['blockName']) || empty($inner_block['attrs']['dragBlockClientId'])) {
				continue;
			}

			// $key = $inner_block['blockName'] . $inner_block['attrs']['dragBlockClientId'];
			$key = dragblock_uid_key($inner_block);
			if (!empty($dragblock_css[$key])) {
				$css .= $dragblock_css[$key];
				unset($dragblock_css[$key]);

				// if (!empty($__DEBUG__)) {
				//     $from = !empty($dragblock_uids[$key]) ? $dragblock_uids[$key] : 'EMPTY';
				//     $to = !empty($dragblock_uids[$uid_key]) ? $dragblock_uids[$uid_key] : 'EMPTY';
				//     var_dump("Placed $key ($from) after $uid_key ($to)");
				// }
			}
		}
	}

	if ($css) {
		$dragblock_css[$uid_key] = $css;
	}

	//     if (!empty($__DEBUG__)) {
	//         // var_dump($uid_key);
	//         var_dump($parsed_block['attrs']['dragBlockClientId']);
	//         !empty($dragblock_uids[$uid_key]) && var_dump($dragblock_uids[$uid_key]);
	//         // !empty($dragblock_css[$uid_key]) && var_dump($dragblock_css[$uid_key]);

	//         var_dump(json_encode($dragblock_css, JSON_PRETTY_PRINT));
	//         echo '

	// ';
	//     }

	return $block_content;
}

function dragblock_uid_key($parsed_block)
{
	$uid_key = $parsed_block['blockName']  . '__' . $parsed_block['attrs']['dragBlockClientId'];

	if (!empty($parsed_block['attrs']['className'])) {
		$uid_key .= '__.' . $parsed_block['attrs']['className'];
	}

	return $uid_key;
}

/**
 * Get json data from theme to replace vairables in the blocks scripts
 */
/**
 * Get theme default data
 */
add_filter('wp_theme_json_data_theme', 'dragblock_appearance_collect_json_data_theme', 10, 1);
function dragblock_appearance_collect_json_data_theme($json)
{
	global $dragblock_theme_json;
	$dragblock_theme_json = $json->get_data();
	return $json;
}

/**
 * Get core default data
 */
add_filter('wp_theme_json_data_default', 'dragblock_appearance_collect_json_data_default', 10, 1);
function dragblock_appearance_collect_json_data_default($json)
{
	global $dragblock_default_json;
	$dragblock_default_json = $json->get_data();
	return $json;
}

/**
 * Get core default data
 */
add_filter('wp_theme_json_data_user', 'dragblock_appearance_collect_json_data_user', 10, 1);
function dragblock_appearance_collect_json_data_user($json)
{
	global $dragblock_user_json;
	$dragblock_user_json = $json->get_data();
	return $json;
}

/**
FRONT END
 * collect all scripts and styles for front-end display
 * 'enqueue_block_assets' = both editor and front-end
 * 'wp_enqueue_scripts' = front pages, require handles
 */
add_action('wp_enqueue_scripts', 'dragblock_appearance_front_scripts');
function dragblock_appearance_front_scripts()
{
	// // @fix: why this also be enqueued in the back-end editor (not the iframe)?
	// dragblock_enqueue('dragblock-app-front', 'build/applications/front/index.js', array('jquery'));

	// // if allow users to modify the default styles, then just need to load an empty css
	// if (DRAGBLOCK_CUSTOM_DEFAULT_STYLE) {
	//     dragblock_enqueue('dragblock-app-front', 'build/applications/front/index.css');
	// } else {
	//     dragblock_enqueue('dragblock-app-front', 'build/applications/front/style-index.css');
	// }


	// global $dragblock_save_css;
	// global $dragblock_save_js;
	global $dragblock_css;

	// var_dump($dragblock_css);
	$dragblock_save_css = implode('', $dragblock_css);

	// var_dump($dragblock_save_css);
	// var_dump($dragblock_save_js);

	// replace variables
	global $dragblock_theme_json;
	global $dragblock_default_json;
	global $dragblock_user_json;


	// update color variables
	// we have to do this on the front-end in order to allow users set the opacity for the orginal color in the back-end
	// !the 'theme' property is added automatically via the $json->get_data(); of wordpress
	////////////////////////////////////////////////////////////////////////
	// If Users changed even one color that predefined in the theme.json, 
	// the system will return a whole settings/color/palette/theme in wp_theme_json_data_user
	if (
		!empty($dragblock_user_json['settings']['color']['palette']['theme'])
	) {
		$dragblock_theme_json['settings']['color']['palette']['theme'] = $dragblock_user_json['settings']['color']['palette']['theme'];
	}

	////////////////////////////////////////////////////////////////////////
	// Color replacement
	// Here are the colors added by users themselves    
	$colors = array();

	if (!empty($dragblock_theme_json['settings']['color']['palette']['theme'])) {
		$colors = array_merge($colors, $dragblock_theme_json['settings']['color']['palette']['theme']);
	}
	if (!empty($dragblock_user_json['settings']['color']['palette']['custom'])) {
		$colors = array_merge($colors, $dragblock_user_json['settings']['color']['palette']['custom']);
	}
	if (!empty($dragblock_default_json['settings']['color']['palette']['default'])) {
		$colors = array_merge($colors, $dragblock_default_json['settings']['color']['palette']['default']);
	}

	// cleanup color array
	foreach ($colors as $key => $c) {
		if (empty($c['slug']) || empty($c['color'])) {
			unset($colors[$key]);
			continue;
		}
	}
	
	////////////////////////////////////////////////////////////////
	// matching colors
	////////////////////////////////////////////////////////////////
	// conver VERSION 0 color markers
	foreach ($colors as $color) {
		// perfect match
		$dragblock_save_css = str_replace(
			COLOR_VAR_V0_START . $color['slug'] . COLOR_VAR_V0_END,
			$color['color'],
			$dragblock_save_css
		);

		// without alpha match
		$dragblock_save_css = str_replace(
			COLOR_VAR_V0_START . $color['slug'] . COLOR_VAR_V0_ALPHA_SEP . COLOR_VAR_V0_END,
			substr($color['color'], 0, 7),
			$dragblock_save_css
		);
	}

	// Convert VERSION 1 color markers
	// mapping color variable to real color or backup color
	$css = explode(COLOR_VAR_V1_START, $dragblock_save_css);
	
	for ($i = 1; $i < count($css); $i++) {
		$parts = explode(COLOR_VAR_V1_END, $css[$i]);	
		
		if (count($parts) < 2) continue; // require {c=__}} to process
		if (strpos($parts[0], '{') !== false) continue; // cannot have { inside {c=__}

		$color_var = explode(COLOR_VAR_V1_BACKUP_SEP, $parts[0]);
		
		$slug = $color_var[0];
		
		$has_alpha_sep = strpos($slug, COLOR_VAR_V1_ALPHA_SEP) !== false;
		if ($has_alpha_sep) {
			$slug = explode(COLOR_VAR_V1_ALPHA_SEP, $slug)[0];
		}
		
		$display = count($color_var) > 1 ? $color_var[1] : ''; // default displaying backup

		foreach ($colors as $c) {
			if ($slug !== $c['slug']) continue;
			$display = $c['color'];
			break;
		}
		// rgba(255, 255, 255, 255)
		// there is no color value longer than 36 characters
		if (empty($display) || strlen($display) > 36) continue;
		
		// display color should not have the alpha in it
		if ($has_alpha_sep) {
			$display = substr($display, 0, 7);
		}
		
		unset($parts[0]);

		$css[$i] = $display . implode(COLOR_VAR_V1_END, $parts);		
	}
	$dragblock_save_css = implode('', $css);

	// conver VERSION 2 colors
	$css = explode(COLOR_VAR_V2_START, $dragblock_save_css);
	for ($i = 1; $i < count($css); $i++) {		
		$parts = explode(COLOR_VAR_V2_END, $css[$i]);
		
		if (count($parts) < 2) continue;
		if (strpos($parts[0], '{') !== false) continue; // cannot have { inside variable value
		$color_var = explode(COLOR_VAR_V2_BACKUP_SEP, $parts[0]);
		if (count($color_var) < 2) continue; // version 2 requires backup colors
		
		$slug = $color_var[0];
		$backup = $color_var[1];
		$alpha = '';
		$has_alpha_sep = strpos($backup, COLOR_VAR_V2_ALPHA_SEP) !== false;
		if ($has_alpha_sep) {
			$backup = explode(COLOR_VAR_V2_ALPHA_SEP, $backup);
			$alpha = $backup[1];
			$backup = $backup[0];
		}
		
		$display = $backup;

		foreach ($colors as $c) {
			if ($slug !== $c['slug']) continue;
			$display = $c['color'];
			break;
		}
		// rgba(255, 255, 255, 255)
		// there should be a color, and value should not longer than 36 characters
		if (empty($display) || strlen($display) > 36) {
			$display = $backup;
		}
		
		// display color should include alpha separately
		if ($alpha) {
			$display = strlen($display) > 7 ? substr($display, 0, 7) : $display;
			$display .= $alpha;
		}
		
		unset($parts[0]);

		$css[$i] = $display . implode(COLOR_VAR_V2_END, $parts);
	}
	$dragblock_save_css = implode('', $css);

	////////////////////////////////////////////////////////////////
	// matching gradient colors
	/*
	gradient elemnts
	{
		'name' => string 'Midnight' (length=8)
		'gradient' => string 'linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%)' (length=60)
		'slug' => string 'midnight' (length=8)
	}
	duotone elements:
	{
		'name' => string 'Blue and orange' (length=15)
      	'colors' => array (size=2)
			0 => string '#1900d8' (length=7)
			1 => string '#ffa96b' (length=7)
      	'slug' => string 'blue-orange' (length=11)
	}
	*/
	$gradients = array();
	
	if (!empty($dragblock_theme_json['settings']['color']['gradients']['theme'])) {
		$gradients = array_merge($gradients, $dragblock_theme_json['settings']['color']['gradients']['theme']);
	}
	if (!empty($dragblock_theme_json['settings']['color']['duotone']['theme'])) {
		$gradients = array_merge($gradients, $dragblock_theme_json['settings']['color']['duotone']['theme']);
	}
	
	if (!empty($dragblock_user_json['settings']['color']['gradients']['default'])) {
		$gradients = array_merge($gradients, $dragblock_user_json['settings']['color']['gradients']['default']);
	}
	if (!empty($dragblock_user_json['settings']['color']['gradients']['custom'])) {
		$gradients = array_merge($gradients, $dragblock_user_json['settings']['color']['gradients']['custom']);
	}
	if (!empty($dragblock_default_json['settings']['color']['duotone']['default'])) {
		$gradients = array_merge($gradients, $dragblock_default_json['settings']['color']['duotone']['default']);
	}
	// we don't use $dragblock_default_json['settings']['color']['gradients']['default']
	// as it will be overwritten by the user_json

	// var_dump($gradients); die();
	
	// cleanup graidents and convert gradient doutones
	foreach ($gradients as $key => $g) {
		if (empty($g['slug'])) {
			unset($gradients[$key]);
			continue;
		}		

		// duotone
		if (empty($g['gradient'])) {			
			if (empty($g['colors']) || count($g['colors']) < 2) {
				unset($gradients[$key]);
				continue;
			}
			$g['colors'][0] .= ' 50%';
			$g['colors'][1] .= ' 50%';
			
			$g['gradient'] = 'linear-gradient(135deg,' . implode(',', $g['colors']) . ')';
			unset($g['colors']);
			$gradients[$key] = $g;
		}
	}
	
	// replace gradient color variables with reall color or backup color
	// $gradient_start = '⮕g=';
	// $gradient_bk = '⬇g='; // fallback gradient
	// $gradient_end = 'g⬅';

	// convert gradient VERSION 1
	$css = explode(GRADIENT_VAR_V1_START, $dragblock_save_css);
	for ($i = 1; $i < count($css); $i++) {
		$parts = explode(GRADIENT_VAR_V1_END, $css[$i]);		
		if (count($parts) < 2) continue; // require {c=__}} to process
		if (strpos($parts[0], '{') !== false) continue; // cannot have { inside {c=__}

		$grad = explode(GRADIENT_VAR_V1_BACKUP_SEP, $parts[0]);

		// the gradient always has the backup
		if (count($grad) < 2) continue;

		$slug = $grad[0];
		$display = $grad[1]; // default displaying backup
		if (!str_ends_with($display, ')')) continue;
		
		foreach ($gradients as $g) {
			if ($slug !== $g['slug']) continue;
			$display = $g['gradient'];
			break;
		}

		unset($parts[0]);
		$css[$i] = $display . implode(GRADIENT_VAR_V1_END, $parts);		
	}
	$dragblock_save_css = implode('', $css);

	// convert gradient VERSION 2
	$css = explode(GRADIENT_VAR_V2_START, $dragblock_save_css);
	for ($i = 1; $i < count($css); $i++) {
		$parts = explode(GRADIENT_VAR_V2_END, $css[$i]);		
		if (count($parts) < 2) continue; // require {c=__}} to process
		if (strpos($parts[0], '{') !== false) continue; // cannot have { inside {c=__}

		$grad = explode(GRADIENT_VAR_V2_BACKUP_SEP, $parts[0]);

		// the gradient always has the backup
		if (count($grad) < 2) continue;

		$slug = $grad[0];
		$display = $grad[1]; // default displaying backup
		if (!str_ends_with($display, ')')) continue;
		
		foreach ($gradients as $g) {
			if ($slug !== $g['slug']) continue;
			$display = $g['gradient'];
			break;
		}

		unset($parts[0]);
		$css[$i] = $display . implode(GRADIENT_VAR_V2_END, $parts);		
	}
	$dragblock_save_css = implode('', $css);

	/**
    Synchronize with the system settings
	 */
	// button font-family for custom drag block button    
	// if (!empty($dragblock_user_json['styles']['elements']['button']['typography']['fontFamily'])) {        
	//     $font_family = $dragblock_user_json['styles']['elements']['button']['typography']['fontFamily'];
	//     $font_family = str_replace('|', '--', $font_family);
	//     $font_family = str_replace('var:preset', '--wp--preset', $font_family);
	//     $dragblock_save_css .= 'button.wp-block-dragblock-wrapper {font-family: var('.$font_family.')';
	// }

	/// add to output css
	if ($dragblock_save_css) {
		wp_add_inline_style(DRAGBLOCK_EDITOR_INIT_SLUG, $dragblock_save_css);

		if (strpos($dragblock_save_css, 'animation-name') !== false) {
			dragblock_enqueue('dragblock-app-animate', 'assets/css/animate.min.css');
		}
	}
}
