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

namespace WeCodeArt\Gutenberg\Blocks;

defined( 'ABSPATH' ) || exit;

use function WeCodeArt\Functions\get_prop;
use function WeCodeArt\Functions\dom;

/**
 * Gutenberg Abstract Dynamic block.
 */
abstract class Dynamic {

	/**
	 * Block namespace.
	 *
	 * @var string
	 */
	protected $namespace = 'wca';

	/**
	 * Block namespace.
	 *
	 * @var string
	 */
	protected $block_name = '';
	
	/**
	 * Register.
	 *
	 * @var boolean
	 */
	protected $register = false;

	/**
	 * Initialize this block type.
	 *
	 * - Hook into WP lifecycle.
	 * - Register the block with WordPress.
	 */
	public function hooks() {
		if ( empty( $this->block_name ) ) {
			_doing_it_wrong( __METHOD__, esc_html__( 'Block name is required.', 'wecodeart' ), '5.6.3' );
			return false;
		}
		
		$this->register();
	}

	/**
	 * Registers the block type with WordPress.
	 */
	private function register() {
		if( $this->register ) {
			call_user_func_array( 'register_block_type', [ $this->get_block_type(), [
				'render_callback' 	=> [ $this, 'get_render_callback' ],
				'attributes'      	=> [ $this, 'get_attributes' ],
				'supports'        	=> [ $this, 'get_supports' ],
				'uses_context'		=> [ $this, 'get_context' ],
			] ] );
		}

		// Block args.
		if( method_exists( $this, 'block_type_args' ) ) {
			\add_filter( 'register_block_type_args', [ $this, 'get_block_args' ], 20, 2 );
		}

		// Block styles.
		\add_action( 'init', [ $this, 'enqueue_styles' ] ); // wp_enqueue_block_styles goes to init hook instead of the usual one.
	}

	/**
	 * Include and render a dynamic block.
	 *
	 * @return	string Block Markup.
	 */
	protected function render() {}

	/**
	 * Load and manipulate HTML with DOMDocument.
	 *
	 * @param 	string $content    Block content. 		Default empty string.
	 * 
	 * @return 	DOMDocument.
	 */
	protected function dom( $content = '' ): \DOMDocument {
		return wecodeart( 'dom' )::create( $content );
	}

	/**
	 * Get block wrapper attributes.
	 *
	 * @return array
	 */
	protected function get_block_wrapper_attributes( $extra_attributes = [] ) {
		$new_attributes = \WP_Block_Supports::get_instance()->apply_block_supports();
	
		if ( empty( $new_attributes ) && empty( $extra_attributes ) ) {
			return [];
		}
	
		// This is hardcoded on purpose.
		// We only support a fixed list of attributes.
		$attributes_to_merge = [ 'class', 'style', 'id' ];
		$attributes          = [];
		foreach ( $attributes_to_merge as $attribute_name ) {
			if ( empty( $new_attributes[ $attribute_name ] ) && empty( $extra_attributes[ $attribute_name ] ) ) {
				continue;
			}
	
			if ( empty( $new_attributes[ $attribute_name ] ) ) {
				$attributes[ $attribute_name ] = $extra_attributes[ $attribute_name ];
				continue;
			}
	
			if ( empty( $extra_attributes[ $attribute_name ] ) ) {
				$attributes[ $attribute_name ] = $new_attributes[ $attribute_name ];
				continue;
			}
	
			$attributes[ $attribute_name ] = $extra_attributes[ $attribute_name ] . ' ' . $new_attributes[ $attribute_name ];
		}
	
		foreach ( $extra_attributes as $attribute_name => $value ) {
			if ( ! in_array( $attribute_name, $attributes_to_merge, true ) ) {
				$attributes[ $attribute_name ] = $value;
			}
		}
	
		if ( empty( $attributes ) ) {
			return [];
		}
	
		return $attributes;
	}

	/**
	 * Get the block type.
	 *
	 * @return string
	 */
	protected function get_block_type() {
		return $this->namespace . '/' . $this->block_name;
	}

	/**
	 * Get block render_callback
	 * 
	 * @return 	string.
	 */
	protected function get_render_callback() {
		return [ $this, 'render' ];
	}

	/**
	 * Get block attributes.
	 *
	 * @return array
	 */
	protected function get_attributes() {
		return [];
	}

	/**
	 * Get the supports array for this block type.
	 *
	 * @see $this->register()
	 *
	 * @return array;
	 */
	protected function get_supports() {
		return [];
	}

	/**
	 * Get block usesContext.
	 *
	 * @return array;
	 */
	protected function get_context() {
		return [];
	}
	
	/**
	 * Get the schema for a value.
	 *
	 * @param  string 	$default  The default value.
	 *
	 * @return array 	Property definition.
	 */
	protected function get_schema( string $type, $default ) {
		$type 	= in_array( $type, [ 'string', 'number', 'boolean', 'list', 'align' ] ) ? $type : 'string';

		$schema = [
			'type'	=> $type,
		];

		switch( $type ) :
			case 'boolean':
				$schema = wp_parse_args( [
					'default' => $default ?: true
				], $schema );
			break;
			case 'string':
				$schema = wp_parse_args( [
					'default' => $default ?: ''
				], $schema );
			break;
			case 'align':
				$schema = wp_parse_args( [
					'type' => 'string',
					'enum' => [ 'left', 'center', 'right', 'wide', 'full' ],
				], $schema );
			break;
			case 'list':
				$schema = wp_parse_args( [
					'type'    => 'array',
					'items'   => [
						'type' => 'number',
					],
					'default' => $default ?: []
				], $schema );
			break;
			default;
		endswitch;

		return $schema;
	}

	/**
	 * Get block args.
	 *
	 * @return array
	 */
	public function get_block_args( array $args, string $block_name ): array {
		if ( $this->get_block_type() === $block_name ) {
			$args	= wp_parse_args( (array) $this->block_type_args( $args ), $args );
		}

		return $args;
	}

	/**
	 * Get block asset handle.
	 *
	 * @return string
	 */
	public function get_asset_handle(): string {
		return 'wp-block-' . $this->block_name;
	}

	/**
	 * Block styles.
	 *
	 * @return 	string Block CSS.
	 */
	public function enqueue_styles() {
		// These are cached styles, so we only generate minified version.
		$styles = wecodeart( 'styles' )::compress( $this->styles() );
		
		if( empty( $styles ) ) {
			return;
		}

		$filesystem = wecodeart( 'files' );
		$filesystem->set_folder( 'cache' );

		$handle		= $this->get_asset_handle();
		$block_css	= $handle . '.css';

		if( ! $filesystem->has_file( $block_css ) ) {
			$filesystem->create_file( $block_css, $styles );
		}

		$registered = get_prop( wp_styles()->registered, $handle );

		if( $this->register || ! $registered ) {
			// Enqueue new
			wp_enqueue_block_style( $this->get_block_type(), [
				'handle'	=> $handle,
				'src'		=> $filesystem->get_file_url( $block_css, true ),
				'path'		=> $filesystem->get_file_url( $block_css ),
				'ver'		=> wecodeart( 'version' )
			] );
		} elseif( $registered ) {
			// Change existing
			$registered->src = $filesystem->get_file_url( $block_css, true );
			$registered->ver = wecodeart( 'version' );
			wp_style_add_data( $handle, 'path', $filesystem->get_file_url( $block_css ) );
		}

		$filesystem->set_folder( '' );
	}

	/**
	 * Block styles.
	 *
	 * @return 	string Block CSS.
	 */
	public function styles() {
		return '';
	}
}
