<?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 Blocks Registry
 * @copyright   Copyright (c) 2025, WeCodeArt Framework
 * @since		5.0.0
 * @version		6.3.7
 */

namespace WeCodeArt\Gutenberg;

defined( 'ABSPATH' ) || exit;

use WeCodeArt\Singleton;
use WeCodeArt\Config\Interfaces\Configuration;
use function WeCodeArt\Functions\get_prop;

/**
 * Gutenberg Blocks Registry.
 */
class Blocks implements Configuration {

	use Singleton;

	/**
	 * The registered Blocks.
	 *
	 * @var Blocks[]
	 */
	protected   $items = [];

	/**
	 * Send to Constructor
	 */
	public function init() {
        // Media Blocks
		$this->register( 'core/media-text', Blocks\Media\Text::class );
		$this->register( 'core/file',	    Blocks\Media\File::class );
        $this->register( 'core/image',	    Blocks\Media\Image::class );
        $this->register( 'core/audio',	    Blocks\Media\Audio::class );
        $this->register( 'core/video',	    Blocks\Media\Video::class );
        $this->register( 'core/embed',	    Blocks\Media\Embed::class );
        $this->register( 'core/cover',	    Blocks\Media\Cover::class );
        $this->register( 'core/gallery',    Blocks\Media\Gallery::class );
        // Text Blocks
        $this->register( 'core/code',	    Blocks\Text\Code::class );
        $this->register( 'core/list',	    Blocks\Text\Lists::class );
        $this->register( 'core/list-item',  Blocks\Text\Lists\Item::class );
        $this->register( 'core/table',	    Blocks\Text\Table::class );
		$this->register( 'core/quote',	    Blocks\Text\Quote::class );
        $this->register( 'core/details',    Blocks\Text\Details::class );
		$this->register( 'core/heading',    Blocks\Text\Heading::class );
		$this->register( 'core/paragraph',  Blocks\Text\Paragraph::class );
		$this->register( 'core/pullquote',  Blocks\Text\Pullquote::class );
        // Design Blocks
		$this->register( 'core/group',      Blocks\Design\Group::class );
		$this->register( 'core/buttons',    Blocks\Design\Buttons::class );
		$this->register( 'core/button',     Blocks\Design\Button::class );
		$this->register( 'core/columns',    Blocks\Design\Columns::class );
		$this->register( 'core/column',     Blocks\Design\Column::class );
		$this->register( 'core/spacer',     Blocks\Design\Spacer::class );
		$this->register( 'core/separator',  Blocks\Design\Separator::class );
		$this->register( 'core/accordion',  Blocks\Design\Accordion::class );
		$this->register( 'core/accordion-item',     Blocks\Design\Accordion\Item::class );
		$this->register( 'core/accordion-heading',  Blocks\Design\Accordion\Heading::class );
        // Widget Blocks
		$this->register( 'core/archives',           Blocks\Widgets\Archives::class );
		$this->register( 'core/calendar',           Blocks\Widgets\Calendar::class );
	    $this->register( 'core/rss',                Blocks\Widgets\RSS::class );
	    $this->register( 'core/latest-posts',       Blocks\Widgets\Posts::class );
		$this->register( 'core/latest-comments',    Blocks\Widgets\Comments::class );
		$this->register( 'core/search',	            Blocks\Widgets\Search::class );
		$this->register( 'core/social-links',       Blocks\Widgets\Social::class );
		$this->register( 'core/social-link',        Blocks\Widgets\Social\Link::class );
        // Navigation Blocks
		$this->register( 'core/navigation',         Blocks\Navigation::class );
		$this->register( 'core/navigation-link',    Blocks\Navigation\Link::class );
		$this->register( 'core/navigation-submenu', Blocks\Navigation\Menu::class );
		$this->register( 'core/home-link',          Blocks\Navigation\Home::class );
		$this->register( 'core/page-list',          Blocks\Navigation\Pages::class );
        // Post Blocks
		$this->register( 'core/post-date',          Blocks\Post\Date::class );
		$this->register( 'core/post-title',         Blocks\Post\Title::class );
		$this->register( 'core/post-terms',         Blocks\Post\Terms::class );
		$this->register( 'core/post-author',        Blocks\Post\Author::class );
		$this->register( 'core/post-author-name',   Blocks\Post\AuthorName::class );
		$this->register( 'core/post-excerpt',       Blocks\Post\Excerpt::class );
		$this->register( 'core/post-content',       Blocks\Post\Content::class );
		$this->register( 'core/post-template',      Blocks\Post\Template::class );
		$this->register( 'core/post-featured-image',Blocks\Post\Image::class );
		$this->register( 'core/post-comments-link', Blocks\Post\Comments::class );
		$this->register( 'core/post-navigation-link',   Blocks\Post\Navigation::class );
        // Comment Blocks
		$this->register( 'core/post-comments-form', Blocks\Comment\Form::class );
		$this->register( 'core/comments-title',     Blocks\Comment\Title::class );
		$this->register( 'core/comment-template',   Blocks\Comment\Template::class );
		$this->register( 'core/comments-pagination-numbers',    Blocks\Comment\Pagination\Numbers::class );
        // Query Blocks
		$this->register( 'core/query',	                    Blocks\Query::class );
		$this->register( 'core/query-title',	            Blocks\Query\Title::class );
		$this->register( 'core/query-pagination-numbers',   Blocks\Query\Pagination\Numbers::class );
        // Site Blocks
		$this->register( 'core/loginout',       Blocks\Site\Login::class );
		$this->register( 'core/site-logo',      Blocks\Site\Logo::class );
		$this->register( 'core/template-part',  Blocks\Site\Template::class );

        // Hooks
        add_action( 'after_setup_theme',    [ $this, 'register_blocks'  ], PHP_INT_MAX );
        add_filter( 'render_block',         [ $this, 'render_template_tags' ], 8, 3 );
	}

    /**
     * Allow custom data to be rendered in blocks.
     *
     * Runs before the block is rendered, so that the custom field
     * string can be used in the shortcode block.
     *
     * @since   6.2.8
     * @version 6.3.7
     *
     * @param   string   $html   Block HTML.
     * @param   array    $block  Block data.
     * @param   WP_Block $object Block context.
     *
     * @return string
     */
    public function render_template_tags( string $html, array $block, \WP_Block $object ): string {
        $block_name = get_prop( $block, [ 'blockName' ], '' );
		$registered = \WP_Block_Type_Registry::get_instance()->get_all_registered();

        if ( ! array_key_exists( $block_name, $registered ) ) {
			return $html;
		}

		$category     = $registered[ $block_name ]->category ?? '';
		$other_blocks = [
			'core/button',
			'core/image',
			'core/navigation-link',
			'core/post-excerpt',
		];

		if ( 'text' !== $category && ! in_array( $block_name, $other_blocks, true ) ) {
			return $html;
		}

        $html = str_replace(
            [ '&#123;', '&#125;', '%7B', '%7D' ],
            [ '{', '}', '{', '}' ],
            $html
        );

        if ( ! str_contains( $html, '{' ) || ! str_contains( $html, '}' ) ) {
			return $html;
		}

        preg_match_all( '#\{(.*?)}#', $html, $matches );

		$without_brackets = $matches[1] ?? [];

		if ( empty( $without_brackets ) ) {
			return $html;
		}

        $post_id      = $instance->context['postId'] ?? get_the_ID();
		$replacements = [];

		foreach ( $without_brackets as $tag ) {
			$tag         = strtolower( $tag );
			$replacement = '';

			if ( shortcode_exists( $tag ) ) {
				continue;
			}

			if ( ! is_null( $post_id ) ) {
				$post_field = get_post_field( $tag, $post_id );

				if ( $post_field ) {
					$replacement = $post_field;
				} else {
					$post_meta = get_post_meta( $post_id, $tag, true );

					if ( $post_meta ) {
						$replacement = $post_meta;
					}
				}
			}

			if ( ! $replacement ) {
				$tags = $this->get_template_tags( $post_id ?: null );

				if ( isset( $tags[ $tag ] ) ) {
                    $replacement = is_callable( $tags[ $tag ] ) ? call_user_func( $tags[ $tag ] ) : $tags[ $tag ];
				}
			}
            
			if ( $replacement ) {
                $replacements[ '{' . $tag . '}' ] = $replacement;
			}
		}

		return str_replace( array_keys( $replacements ), array_values( $replacements ), $html );
    }

    /**
	 * Get template tags.
	 *
	 * @since   6.3.7
	 *
	 * @param   ?int $post_id
	 *
	 * @return  array
	 */
	private function get_template_tags( ?int $post_id ): array {
        $tags = [
            'copy'         => '&copy;',
            'year'         => gmdate( 'Y' ),
            'current_year' => gmdate( 'Y' ),
            'date'         => gmdate( 'm/d/Y' ),
            'home_url'     => esc_url( home_url() ),
            'site_title'   => get_bloginfo( 'name', 'display' ),
            'site_name'    => get_bloginfo( 'name', 'display' ),
            'theme'        => sprintf( '<a href="%s" target="_blank">%s</a>', 'https://www.wecodeart.com/', 'WeCodeArt Framework' )
        ];

		$post_type_object = get_post_type_object( get_post_type( $post_id ) );

		if ( $post_type_object ) {
			$tags['post_type_label'] = $post_type_object->label;
		}

        $tags['read_time'] = static function () use ( $post_id ): string {
            $per_minute = apply_filters( 'wecodeart/filter/words_per_minute', 200 );
            $words      = str_word_count( strip_tags( get_post_field( 'post_content', $post_id ) ) );
            $minutes    = floor( $words / $per_minute );

            if( $minutes < 1 ) {
                return esc_html__( 'Less than a minute to read.', 'wecodeart' );
            }

            return sprintf(
                _nx( '%1$s minute to read', '%1$s minutes to read', $minutes, 'comments title', 'wecodeart' ),
                number_format_i18n( $minutes ),
            );
        };

		return apply_filters( 'wecodeart/filter/template/tags', $tags, $post_id );
	}

    /**
     * Register hooks
	 *
     * @return void
	 */
    public function register_blocks() {
        do_action( 'wecodeart/gutenberg/blocks/register', $this );

        return array_map( fn( $class ) => $class::get_instance()->hooks(), $this->all() );
	}

	/**
     * Set a given module value.
     *
     * @param  array|string  $key
     * @param  mixed   $value
     *
     * @return void
     */
    public function register( $key, $value = null ) {
        $this->set( $key, $value );
	}
	
    /**
     * Set a given module value.
     *
     * @param  array|string  $key
     * @param  mixed   $value
     *
     * @return void
     */
    public function set( $key, $value = null ) {
        $keys = is_array( $key ) ? $key : [ $key => $value ];

        foreach ( $keys as $key => $value ) {
            $this->items[$key] = apply_filters( "wecodeart/gutenberg/blocks/set/{$key}", $value );
        }
	}

	/**
     * Determine if the given Blocks value exists.
     *
     * @param  string  $key
     *
     * @return bool
     */
    public function has( $key ) {
        return isset( $this->items[$key] );
    }

    /**
     * Get the specified Blocks value.
     *
     * @param  string  $key
     * @param  mixed   $default
     *
     * @return mixed
     */
    public function get( $key, $default = null ) {
        if ( ! isset( $this->items[$key] ) ) {
            return $default;
        }

        return apply_filters( "wecodeart/gutenberg/blocks/get/{$key}", $this->items[$key] );
    }
	
	/**
     * Removes module from the container.
     *
     * @param  string  $key
     *
     * @return bool
     */
    public function forget( $key ) {
		unset( $this->items[$key] );
    }

    /**
     * Get all of the module items for the application.
     *
     * @return array
     */
    public function all() {
        return $this->items;
    }
}