<?php
/**
 * WeCodeArt Framework
 *
 * WARNING: This file is part of the core WeCodeArt Framework. DO NOT edit this file under any circumstances.
 * Please do all modifications in the form of a child theme.
 *
 * @package		WeCodeArt Framework
 * @subpackage  Gutenberg
 * @copyright   Copyright (c) 2025, WeCodeArt Framework
 * @since		4.0.3
 * @version		6.4.8
 */

namespace WeCodeArt;

defined( 'ABSPATH' ) || exit;

use WeCodeArt\Singleton;
use WeCodeArt\Config\Traits\Asset;
use function WeCodeArt\Functions\get_prop;
use function WeCodeArt\Functions\get_json_color;

/**
 * Handles Gutenberg Theme Functionality.
 */
class Gutenberg {

	use Singleton;
	use Asset;

	/**
	 * The Gutenberg Config.
	 *
	 * @var config[]
	 */
	protected $config = [];

	/**
	 * Class Init.
	 *
	 * @return void
	 */
	public function init() {
		// Setup Config
		$this->config = wecodeart_config( 'gutenberg', [] );

		// Block Categories.
		add_filter( 'block_categories_all',			[ $this, 'block_category' 			], 20, 1 );
		
		// Editor Settings.
		add_filter( 'block_editor_settings_all',	[ $this, 'block_editor_settings' 	], 20, 2 );
		
		// Block Supports
		add_filter( 'register_block_type_args',		[ $this, 'block_type_args' 			], 20, 2 );
		
		// Editor Assets.
		add_action( 'enqueue_block_editor_assets', 	[ $this, 'block_editor_assets' 		], 20, 1 );

		// Frontend Assets.
		add_action( 'wp_enqueue_scripts',			[ $this, 'frontend_assets'			], 20, 1 );

		// Theme Support.
		add_action( 'after_setup_theme', 			[ $this, 'after_setup_theme' 		], 100 );

		// Admin.
		add_action( 'admin_init', 					[ $this, 'admin_init' ] );

		// Skip links - those are handled in JS file.
		remove_action( 'wp_footer', 				'the_block_template_skip_link' );

		// Blocks.
		Gutenberg\Blocks::get_instance();
		// Styles.
		Gutenberg\Styles::get_instance();
		// Paterns.
		Gutenberg\Patterns::get_instance();
	}

	/**
	 * Gurenberg WCA Category
	 *
	 * @param  array $categories - Current guttenberg cats.
	 *
	 * @return array
	 */
	public function block_category( $categories ) {
		return array_merge( $categories, [ [
			'slug' 	=> 'wca',
			'title' => __( 'WeCodeArt', 'wecodeart' ),
		] ] );
	}

	/**
	 * Block register args.
	 *
	 * @param	array	$args
	 * @param	string	$block_name
	 *
	 * @return 	array
	 */
	public function block_type_args( array $args, string $block_name ): array {
		if( str_starts_with( $block_name, 'core/' ) && ! in_array( $block_name, self::get_restricted_blocks(), true ) ) {
			$support	= get_prop( $args, [ 'supports' ], [] );
			
			$args		= wp_parse_args( [
				'supports'	=> wp_parse_args( [
					'__experimentalStyles' => true,
				], $support ),
			], $args );
		}

		return $args;
	}

	/**
	 * Add new block editor settings for custom classes.
	 *
	 * @param array  $settings 	The editor settings.
	 * @param object $post 		The post being edited.
	 *
	 * @return array Returns updated editors settings.
	 */
	public function block_editor_settings( array $settings, $post ): array {
		$settings['fontLibraryEnabled'] = true;

		if ( ! isset( $settings[ 'wecodeart' ] ) ) {
			$settings[ 'wecodeart' ] = apply_filters( 'wecodeart/filter/gutenberg/settings', [], $post );
		}

		return $settings;
	}

	/**
	 * Editor assets.
	 *
	 * @return  void
	 */
	public function block_editor_assets() {
		// Inline
		$data = apply_filters( 'wecodeart/filter/gutenberg/localize', [
			'theme' 	=> [
				'name'		=> wecodeart( 'name' ),
				'version' 	=> wecodeart( 'version' )
			]
		] );
		
		wp_register_script( $this->make_handle( 'inline' ), '' );
		wp_enqueue_script( $this->make_handle( 'inline' ) );
		wp_add_inline_script( $this->make_handle( 'inline' ), 'window.wecodeartGutenberg = ' . wp_json_encode( $data ) . ';', 'before' );

		// Gutenberg editor assets.
		wp_enqueue_script( $this->make_handle(), $this->get_asset( 'js', 'gutenberg/editor' ), [
			'wp-blocks',
			'wp-i18n',
			'wp-element',
			'wp-plugins',
			'wp-components',
			'wp-compose',
			'wp-edit-post',
			'wp-api',
			'wp-editor',
			'wp-hooks',
			'lodash',
			$this->make_handle( 'inline' )
		], wecodeart( 'version' ) );

		wp_set_script_translations( $this->make_handle(), 'wecodeart', wecodeart_config( 'directories' )['languages'] );
		
		// CodeMirror assets.
		wp_enqueue_code_editor( [ 'type' => 'text/html' ] );
		wp_add_inline_script( 'wp-codemirror', 'window.CodeMirror = wp.CodeMirror;' );
		wp_enqueue_script(
			$this->make_handle( 'codemirror-fs' ), 
			$this->get_asset( 'js', 'admin/codemirror-fs' ),
			[ 'wp-codemirror' ],
			wecodeart( 'version' )
		);
		
		$code_mirror = ''; // Adds a border to CodeMirror to match WP and fixes height.
		$code_mirror .= '.CodeMirror.CodeMirror-wrap{height:auto;margin-bottom:1rem;border:1px solid #949494;z-index:0;}';
		wp_add_inline_style( 'wp-editor', $code_mirror );
	}

	/**
	 * Frontend assets.
	 *
	 * @return 	void
	 */
	public function frontend_assets() {
		// Manage Styles.
		wp_deregister_style( 'wp-block-library' );		// WordPress Core
		wp_dequeue_style( 'wp-block-library' );         // WordPress Core
        wp_deregister_style( 'wp-block-library-theme' );// WordPress Core
        wp_dequeue_style( 'wp-block-library-theme' );   // WordPress Core

		$style = '';

		// Box Sizing
		$style .= '*,*::before,*::after {box-sizing: border-box;}';
		// Colors RGB as CSS var
		$palette 	= wecodeart_json( [ 'settings', 'color', 'palette' ], [] );

		foreach( $palette as $item ) {
			$slug 	= get_prop( $item, [ 'slug' ] );
			$value 	= wecodeart( 'styles' )::hex_to_rgb( get_prop( $item, [ 'color' ] ), 1, true );
			$value  = join( ', ', wp_array_slice_assoc( $value, [ 'r', 'g', 'b' ] ) );
			
			$style .= sprintf( '.has-%s-color{--wp--color--rgb:%s}', $slug, $value );
			$style .= sprintf( '.has-%s-background-color{--wp--background--rgb:%s}', $slug, $value );
		}

		wp_add_inline_style( 'global-styles', $style );
	}

	/**
	 * Support
	 *
	 * @access public
	 */
	public function after_setup_theme() {
		\add_editor_style( $this->get_asset( 'css', 'frontend' ) );
		\add_editor_style( $this->get_asset( 'css', 'gutenberg/editor' ) );
		\add_filter( 'wp_theme_json_data_theme', [ $this, 'link_hover_brightness' ], 20, 1 );
	}

	/**
	 * Adjust link hover brightness automatically.
	 *
	 * @param 	object 	$theme_json
	 *
	 * @return 	object
	 */
	public function link_hover_brightness( object $theme_json ): object {
		$link	= get_json_color( [ 'styles', 'elements', 'link', 'color', 'text' ] );

		if( $link ) {
			$data = $theme_json->get_data();

			// Adjust hover brightness.
			$data['styles']['elements']['link'][':hover'] = wp_parse_args( [
				'color' => [
					'text' => wecodeart( 'styles' )::hex_brightness( $link, -25 )
				]
			], get_prop( $data, [ 'styles', 'elements', 'link', ':hover' ], [] ) );

			// Update object.
			$theme_json->update_with( $data );
		}

		return $theme_json;
	}

	/**
	 * Removes the Site Editor link from the admin.
	 *
	 * @return void
	 */
	public function admin_init() {
		// Developer mode will allways have access to FSE.
		if( wecodeart_if( 'is_dev_mode' ) ) {
			return;
		}

		// Developers can turn off FSE admin (eg: on production).
		if( get_prop( wecodeart_config( 'gutenberg' ), [ 'editor' ], true ) === true ) {
			return;
		}

		remove_submenu_page( 'themes.php', 'site-editor.php' );
	}

	/**
	 * Restricted core blocks.
	 *
	 * @param 	array 	$blocks
	 *
	 * @return 	array
	 */
	public static function get_restricted_blocks( array $blocks = [] ): array {
		return apply_filters( 'wecodeart/filter/gutenberg/restricted', wp_parse_args( $blocks, [
			'core/block',
			'core/html',
			'core/freeform',
			'core/missing',
			'core/more',
			'core/nextpage',
			'core/pattern',
			'core/shortcode',
			'core/calendar',
			'core/archives',
			'core/rss',
			'core/tag-cloud',
			'core/latest-comments'
		] ) );
	}

	/**
	 * Registered core blocks.
	 *
	 * @param 	bool 	$restricted
	 *
	 * @return 	array
	 */
	public static function get_core_blocks( bool $restricted = true ): array {
		$all_blocks = \WP_Block_Type_Registry::get_instance()->get_all_registered();
		$all_blocks = array_keys( $all_blocks );

		$core_blocks= [];

		foreach ( $all_blocks as $slug ) { 
			if( str_starts_with( $slug, 'core/' ) ) {
				$core_blocks[] = $slug;
			}
		}

		if( $restricted === false ) {
			$core_blocks = array_diff( $core_blocks, self::get_restricted_blocks() );
		}

		return $core_blocks;
	}
}