<?php
namespace SabaiApps\Directories\Component\WordPress\Helper;

use SabaiApps\Directories\Application;
use SabaiApps\Directories\Component\WordPress\Block\IBlock;
use SabaiApps\Directories\Exception;

/**
 * BlocksHelper provides methods to register, initialize, and render WordPress blocks for SabaiApps components.
 */
class BlocksHelper {

	/**
	 * Returns all available blocks for SabaiApps components.
	 *
	 * @param Application $application
	 * @param bool        $useCache
	 * @return array
	 */
	public function help( Application $application, $useCache = true ) {
		if ( ! $useCache
			|| ( ! $blocks = $application->getPlatform()->getCache( 'wordpress_blocks' ) )
		) {
			$blocks = array();
			foreach ( $application->InstalledComponentsByInterface( 'WordPress\IBlocks' ) as $component_name ) {
				if ( ! $application->isComponentLoaded( $component_name )
					|| ( ! $block_names = $application->getComponent( $component_name )->wordpressGetBlockNames() )
				) {
					continue;
				}

				foreach ( $block_names as $block_name ) {
					if ( ( ! $block = $application->getComponent( $component_name )->wordpressGetBlock( $block_name ) )
						|| ( ! $info = $block->wordpressBlockInfo() )
					) {
						continue;
					}

					$blocks[ $block_name ] = array(
						'component' => $component_name,
						'info'      => $info,
					);
				}
			}
			$application->getPlatform()->setCache( $blocks, 'wordpress_blocks', 0 );
		}

		return $blocks;
	}

	private $_impls = array();

	/**
	 * Returns the block implementation object for a given block name.
	 *
	 * @param Application $application
	 * @param string      $blockName
	 * @param bool        $returnFalse
	 * @param bool        $useCache
	 * @return IBlock|false
	 * @throws Exception\UnexpectedValueException
	 */
	public function impl( Application $application, $blockName, $returnFalse = false, $useCache = true ) {
		if ( ! isset( $this->_impls[ $blockName ] ) ) {
			if ( ( ! $blocks = $this->help( $application, $useCache ) )
				|| ! isset( $blocks[ $blockName ]['component'] )
				|| ( ! $application->isComponentLoaded( $blocks[ $blockName ]['component'] ) )
			) {
				if ( $returnFalse ) {
					return false;
				}
				throw new Exception\UnexpectedValueException( sprintf( 'Invalid block: %s', $blockName ) );
			}
			$this->_impls[ $blockName ] = $application->getComponent( $blocks[ $blockName ]['component'] )->wordpressGetBlock( $blockName );
		}

		return $this->_impls[ $blockName ];
	}

	/**
	 * Initializes and registers all blocks, scripts, and styles for the block editor.
	 *
	 * @param Application $application
	 * @param bool        $force
	 */
	public function init( Application $application, $force = false ) {
		$single_only = $site_editor_only = array();
		$blocks      = $this->help( $application, $force );
		foreach ( array_keys( $blocks ) as $name ) {
			$info  = $blocks[ $name ]['info'];
			$_name = str_replace( '_', '-', $name );
			// Is it single post/term/user or site editor only block?
			if ( ! empty( $info['single_only'] ) ) {
				$single_only[] = 'sabaiapps/drts-' . $name;
			}
			if ( ! empty( $info['site_editor_only'] ) ) {
				$site_editor_only[] = 'sabaiapps/drts-' . $name;
			}
			unset( $info['single_only'], $info['site_editor_only'] );
			// Register block.json
			$package = null;
			if ( isset( $info['package'] ) ) {
				$package = $info['package'];
				unset( $info['package'] );
			}
			$block_type = $application->getPlatform()->getAssetsDir( $package ) . '/blocks/drts-' . $_name;
			// Register scripts
			foreach ( array( 'editor_script', 'script', 'view_script' ) as $script_type ) {
				if ( ! isset( $info[ $script_type ] ) ) {
					continue;
				}

				foreach ( (array) $info[ $script_type ] as $handle => $script ) {
					$handle = 'drts-wordpress-block-' . $script_type . '-' . $handle;
					wp_register_script( $handle, $script['src'], $script['deps'] );
					$info[ $script_type . '_handles' ][] = $handle;
				}
				unset( $info[ $script_type ] );
			}
			// Register styles
			foreach ( array( 'editor_style', 'style', 'view_style' ) as $style_type ) {
				if ( empty( $info[ $style_type ] ) ) {
					continue;
				}

				foreach ( (array) $info[ $style_type ] as $handle => $style ) {
					$handle = 'drts-wordpress-block-' . $style_type . '-' . $handle;
					wp_register_style( $handle, $style['src'], $style['deps'] );
					$info[ $style_type . '_handles' ][] = $handle;
				}
				unset( $info[ $style_type ] );
			}

			// Set default properties
			$info += array(
				'version'     => Application::VERSION,
				'api_version' => 3,
				'category'    => 'sabaiapps-drts',
				'icon'        => 'smiley',
				'textdomain'  => 'directories-pro',
			);

			if ( isset( $info['title'] ) ) {
				$info['title'] = 'Directories: ' . $info['title'];
			}

			if ( ! isset( $info['render'] )
				|| $info['render'] !== false
			) {
				$info['render_callback'] = array( $application, 'WordPress_Blocks_renderBlock' );
			}
			unset( $info['render'] );

			unset( $info['bundle_type'], $info['view_mode'] );
			register_block_type( $block_type, $info );
		}
		if ( ! empty( $blocks )
			&& is_admin()
		) {
			add_action(
				version_compare( $GLOBALS['wp_version'], '6.3', '>=' ) ? 'enqueue_block_assets' : 'enqueue_block_editor_assets',
				array( $application, 'WordPress_Blocks_enqueueBlockEditorAssets' )
			);
		}

		// Add custom block category
		add_filter(
			version_compare( $GLOBALS['wp_version'], '5.8', '>=' ) ? 'block_categories_all' : 'block_categories',
			function ( $categories ) {
				$categories[] = array(
					'slug'  => 'sabaiapps-drts',
					'title' => 'Directories',
				);
				return $categories;
			}
		);

		add_filter(
			'allowed_block_types_all',
			function ( $allowed_blocks, $editor_context ) use ( $application, $single_only, $site_editor_only ) {
				$is_site_editor = isset( $editor_context->name ) && $editor_context->name === 'core/edit-site';
				if ( $is_site_editor ) {
					if ( ! empty( $single_only ) ) {
						// Get the current template being edited
						$post_id = filter_input( INPUT_GET, 'postId', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
						if ( $post_id ) {
							// Decode and extract the slug
							$decoded_post_id = urldecode( $post_id );
							// Extract the template slug (after the theme namespace)
							if ( strpos( $decoded_post_id, '//' ) !== false ) {
								list(, $template_slug) = explode( '//', $decoded_post_id, 2 );
								if ( ! in_array( $template_slug, array( 'drts-post', 'drts-term', 'drts-user' ) )
								&& ! $this->_isPostTypeTemplate( $application, $template_slug )
								&& ! $this->_isTaxonomyTemplate( $application, $template_slug )
								) {
									if ( $allowed_blocks === true ) {
										$allowed_blocks = array_keys( \WP_Block_Type_Registry::get_instance()->get_all_registered() );
									}
									// Remove single post/term/user only blocks
									$allowed_blocks = array_values( array_diff( $allowed_blocks, $single_only ) );
								}
							}
						}
					}
				} else {
					// Not in site editor
					if ( ! empty( $site_editor_only ) ) {
						if ( $allowed_blocks === true ) {
							$allowed_blocks = array_keys( \WP_Block_Type_Registry::get_instance()->get_all_registered() );
						}
						// Remove site editor only blocks
						$allowed_blocks = array_values( array_diff( $allowed_blocks, $site_editor_only ) );
					}
				}
				return $allowed_blocks;
			},
			10,
			2
		);

		register_block_pattern_category( 'sabaiapps-drts', array( 'label' => 'Directories' ) );
		register_block_pattern(
			'sabaiapps/directories-pro-hero-template',
			array(
				'title'       => 'Hero Section with Search',
				'description' => 'A beautiful gradient hero section featuring the directory search shortcode.',
				'content'     => '<!-- wp:cover {"dimRatio":90,"isUserOverlayColor":true,"minHeightUnit":"px","customGradient":"linear-gradient(110deg,rgb(48,207,208) 0%,rgb(51,8,103) 100%)","metadata":{"categories":["drts"],"patternName":"directories-pro/hero-template","name":"Hero Section with Search"},"align":"full","style":{"spacing":{"padding":{"top":"54px","bottom":"54px"},"margin":{"top":"0px","bottom":"0px"}}},"layout":{"type":"constrained"}} -->
<div class="wp-block-cover alignfull drts-wordpress-block-pattern is-style-drts-wave" style="margin-top:0px;margin-bottom:0px;padding-top:54px;padding-bottom:54px"><span aria-hidden="true" class="wp-block-cover__background has-background-dim-90 has-background-dim has-background-gradient" style="background:linear-gradient(110deg,rgb(48,207,208) 0%,rgb(51,8,103) 100%)"></span><div class="wp-block-cover__inner-container"><!-- wp:paragraph {"align":"center","style":{"spacing":{"margin":{"bottom":"80px","top":"0px"}}}} -->
<p class="has-text-align-center" style="margin-top:0px;margin-bottom:80px">For Businesses, Creators, and Communities</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph {"align":"center","placeholder":"Write title…","style":{"spacing":{"margin":{"top":"36px","bottom":"0px"}}},"fontSize":"x-large"} -->
<p class="has-text-align-center has-x-large-font-size" style="margin-top:36px;margin-bottom:0px"><strong>Discover. Connect. Grow Together.</strong></p>
<!-- /wp:paragraph -->
<!-- wp:paragraph {"align":"center","style":{"spacing":{"margin":{"top":"0px","bottom":"80px","left":"0"}}},"fontSize":"medium"} -->
<p class="has-text-align-center has-medium-font-size" style="margin-top:0px;margin-bottom:80px;margin-left:0">A Powerful Directory Platform for WordPress.</p>
<!-- /wp:paragraph -->
<!-- wp:group {"style":{"spacing":{"margin":{"top":"0","bottom":"54px"}}},"layout":{"type":"constrained","contentSize":"850px","wideSize":"1000px"}} -->
<div class="wp-block-group" style="margin-top:0;margin-bottom:54px"><!-- wp:sabaiapps/drts-search {"bundle":"","btnText":"","navLinkColor":"light","bgColor":"light","shadowColor":"dark","size":"lg","filter":true} /--></div>
<!-- /wp:group --></div></div>
<!-- /wp:cover -->',
				'categories'  => array( 'sabaiapps-drts' ),
			)
		);
		register_block_style(
			'core/cover',
			array(
				'name'  => 'drts-wave',
				'label' => 'Wave',
			)
		);
		register_block_style(
			'core/cover',
			array(
				'name'  => 'drts-grid',
				'label' => 'Grid',
			)
		);
		register_block_style(
			'core/cover',
			array(
				'name'  => 'drts-stripe',
				'label' => 'Stripe',
			)
		);
	}

	/**
	 * Checks if the template is a post type template.
	 *
	 * @param Application $application
	 * @param string      $template
	 * @return bool
	 */
	protected function _isPostTypeTemplate( Application $application, $template ) {
		if ( 0 !== strpos( $template, 'single-' ) ) {
			return false;
		}

		$post_type = substr( $template, strlen( 'single-' ) );
		return $application->getComponent( 'WordPressContent' )->hasPostType( $post_type );
	}

	/**
	 * Checks if the template is a taxonomy template.
	 *
	 * @param Application $application
	 * @param string      $template
	 * @return bool
	 */
	protected function _isTaxonomyTemplate( Application $application, $template ) {
		if ( 0 !== strpos( $template, 'taxonomy-' ) ) {
			return false;
		}

		$taxonomy = substr( $template, strlen( 'taxonomy-' ) );
		return $application->getComponent( 'WordPressContent' )->hasTaxonomy( $taxonomy );
	}

	/**
	 * Enqueues block editor assets and localizes block variables.
	 *
	 * @param Application $application
	 */
	public function enqueueBlockEditorAssets( Application $application ) {
		// Enqueue frontend JS files.
		/*
		Temporarily disable loading of core JS as content rendered inside block editor does not seem to execute JS (WP bug?).
		$application->getPlatform()->loadMainCoreCss();
		*/
		// Enqueue frontend CSS files.
		$application->getPlatform()->loadMainCoreCss();

		$blocks = $this->help( $application );
		foreach ( array_keys( $blocks ) as $name ) {
			if ( ! $block = $this->impl( $application, $name, true ) ) {
				continue;
			}

			$_name  = str_replace( '_', '-', $name );
			$handle = 'sabaiapps-drts-' . $_name . '-editor-script';
			if ( $_vars = $block->wordpressBlockEditorVars() ) {
				wp_localize_script( $handle, 'drts_wordpress_block_editor_vars_' . $name, $_vars );
			}
			// Allow block to do something
			$block->wordpressBlockOnEnqueueEditorAssets( $handle );
		}
	}

	/**
	 * Renders a block on the frontend or in the editor.
	 *
	 * @param Application $application
	 * @param array       $attributes
	 * @param string|null $content
	 * @param object      $block
	 * @return string
	 */
	public function renderBlock( Application $application, $attributes, $content, $block ) {
		// Render callback called from the editor or the frontend?
		$is_block_editor_request = defined( 'REST_REQUEST' ) && REST_REQUEST;

		if ( ! defined( 'DRTS_WORDPRESS_IS_RENDER_BLOCK' ) ) {
			define( 'DRTS_WORDPRESS_IS_RENDER_BLOCK', true );
		}

		if ( empty( $block->name ) ) {
			$error = 'Block name may not be enmpty';
		} elseif ( ( strpos( $block->name, 'sabaiapps/drts-' ) !== 0 )
			|| ( ! $block_name = substr( $block->name, strlen( 'sabaiapps/drts-' ) ) )
		) {
			$error = 'Invalid block name: ' . $block->name;
		} else {
			try {
				$block_name = str_replace( '-', '_', $block_name );
				$block      = $this->impl( $application, $block_name );
				$rendered   = $block->wordpressBlockRender( (array) $attributes, $content, $is_block_editor_request );
				if ( ! is_string( $rendered )
					|| ! strlen( $rendered )
				) {
					return $is_block_editor_request ? $block->wordpressBlockPlaceholder( (array) $attributes, $content ) : '';
				}
				return $rendered;
			} catch ( Exception\IException $e ) {
				$error = $e->getMessage();
			}
		}
		if ( isset( $error ) ) {
			if ( $is_block_editor_request ) {
				return $error;
			}

			$application->logError( $error );
		}
		return '';
	}

	/**
	 * Checks if the current theme is a Full Site Editing (FSE) theme.
	 *
	 * @param Application $application
	 * @return bool
	 */
	public function isFseTheme( Application $application ) {
		if ( function_exists( 'wp_is_block_theme' ) ) {
			return (bool) wp_is_block_theme();
		} elseif ( function_exists( 'gutenberg_is_fse_theme' ) ) {
			return (bool) gutenberg_is_fse_theme();
		}
		return false;
	}
}
