<?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 	Support\Assets
 * @copyright   Copyright (c) 2025, WeCodeArt Framework
 * @since 		5.4.0
 * @version		6.6.8
 */

namespace WeCodeArt\Support;

defined( 'ABSPATH' ) || exit;

use WeCodeArt\Config\Traits\{ Asset, Singleton, No_Conditionals };
use WeCodeArt\Config\Interfaces\Integration;
use function WeCodeArt\Functions\get_prop;

/**
 * The Fonts object.
 */
final class Assets implements Integration {

	use Singleton;
	use Asset;
	use No_Conditionals;

	/**
	 * Container of valid properties.
	 *
	 * @var array
	 */
	const VALID_PROPERTIES = [
		'path',
		'deps',
		'version',
		'footer',
		'inline',
		'locale',
		'where',
		'load',
		'media',
		'rtl'
	];

	/**
	 * Asset
	 *
	 * @since  	5.4.5
	 * @var 	object
	 */
	public 	$Asset	= null;

	/**
	 * Contains an array of script handles registered.
	 * 
	 * @since  	6.0.0
	 * @var 	array
	 */
	private static $scripts = [];

	/**
	 * Contains an array of script handles registered.
	 *
	 * @since  	6.0.0
	 * @var 	array
	 */
	private static $styles = [];

	/**
	 * Send to Constructor
	 */
	public function init() {
		$this->Asset = ( new Assets\Asset( wecodeart_config() ) );
	}

	/**
	 * Register hooks
	 */
	public function register_hooks(): void {
		\add_action( 'wp_enqueue_scripts',	[ $this, 'core'		], 20 );
		\add_action( 'wp_enqueue_scripts',	[ $this, 'enqueue'	], PHP_INT_MAX );
	}

	/**
	 * Enqueue Front-End Core Assets
	 *
	 * @since	6.0.0
	 * @version	6.4.5
	 */
	public function core(): void {
		// Styles
		$this->add_style( 'global-styles', [
			'inline'	=> 'file:' . $this->get_asset( 'css', 'frontend' ),
		] );

		// Scripts
		foreach( [ 'backdrop', 'focustrap', 'template', 'toast' ] as $handle ) {
			$this->add_script( $this->make_handle( $handle ), [
				'path' 		=> $this->get_asset( 'js', 'plugins/' . $handle ),
				'deps'		=> [ $this->make_handle() ],
				'load'		=> false,
			] );
		}

		$wecodeart = [ 
			'templateDirectory' => get_template_directory_uri(),
			'styleDirectory'	=> is_child_theme() ? get_stylesheet_directory_uri() : null,
			'version'			=> wecodeart( 'version' ),
			'isDevMode'			=> wecodeart_if( 'is_dev_mode' ),
			'plugins'			=> [],
			'locale'			=> [
				'skipLink' => esc_html__( 'Skip to content', 'wecodeart' )
			]
		];
		
		$this->add_script( $this->make_handle(), [
			'path' 		=> $this->get_asset( 'js', 'frontend' ),
			'deps'		=> [ 'wp-hooks' ],
			'locale'	=> array_filter( $wecodeart, fn( $value ) => $value !== null ),
			'inline'	=> 'document.addEventListener("DOMContentLoaded",function(){new wecodeart.Scripts();});',
		] );

		// Script Modules
		foreach( [ 'collapse', 'offcanvas', 'modal', 'toast', 'dropdown' ] as $handle ) {
			\wp_register_script_module(
				'@wecodeart/' . $handle,
				$this->get_asset( 'js', 'modules/' . $handle ),
				[ '@wordpress/interactivity' ],
				wecodeart( 'version' )
			);
		}
	}

	/**
     * Update a given asset.
     *
     * @param  string	$handle
     * @param  array   	$data
     * @param  string	$type
     *
     * @return mixed
     */
    public function update( string $handle, array $data = [], string $type = '' ) {
		if( ! in_array( $type, [ 'style', 'script' ] ) ) {
			return _doing_it_wrong(
				__CLASS__, 
				sprintf( esc_html__( 'When using "%s" method you must define the 3rd parameter (style or script).', 'wecodeart' ), __FUNCTION__ ),
				'6.0.0'
			);
		}

		$data = wp_array_slice_assoc( $data, self::VALID_PROPERTIES );

		switch( $type ) :
			case 'style':
				if( array_key_exists( $handle, self::$styles ) ) {
					self::$styles[$handle] = wp_parse_args( $data, self::$styles[$handle] );
				}
			break;
			case 'script':
				if( array_key_exists( $handle, self::$scripts ) ) {
					self::$scripts[$handle] = wp_parse_args( $data, self::$scripts[$handle] );
				}
			break;
		endswitch;

		return $this;
	}

	/**
     * Add a given style.
     *
     * @param  string	$handle
     * @param  array   	$data
     *
     * @return void
     */
    public function add_style( string $handle, array $data = [] ): void {
		// Valid Args
		$data = wp_array_slice_assoc( $data, self::VALID_PROPERTIES );
		$data = wp_parse_args( $data, [
			'handle' 	=> $handle,
			'src'    	=> '',
			'deps'   	=> [],
			'version' 	=> wecodeart( 'version' ),
			'media'		=> 'all',
		] );

		// Registration Logic
		$args = [
			get_prop( $data, 'handle' ),
			get_prop( $data, 'path', false ),
			get_prop( $data, 'deps' ),
			get_prop( $data, 'version' ),
			get_prop( $data, 'media' )
		];

		if ( ! in_array( $handle, self::$styles, true ) && ! wp_style_is( $handle, 'registered' ) ) {
			wp_register_style( ...$args );
		}

		self::$styles[$handle] = $data;
	}

	/**
     * Add a given script.
     *
     * @param  string	$handle
     * @param  array   	$data
     *
     * @return void
     */
    public function add_script( string $handle, array $data = [] ): void {
		// Valid Args
		$data = wp_array_slice_assoc( $data, self::VALID_PROPERTIES );
		$data = wp_parse_args( $data, [
			'handle' 	=> $handle,
			'src'    	=> '',
			'deps'   	=> [],
			'version' 	=> wecodeart( 'version' ),
			'footer' 	=> true,
		] );

		// Registration Logic
		$args = [
			get_prop( $data, 'handle' ),
			get_prop( $data, 'path', false ),
			get_prop( $data, 'deps' ),
			get_prop( $data, 'version' ),
			get_prop( $data, 'footer' )
		];

		if ( ! in_array( $handle, self::$scripts, true ) && ! wp_script_is( $handle, 'registered' ) ) {
			wp_register_script( ...$args );
		}

		self::$scripts[$handle] = $data;
	}

	/**
	 * Load Assets
	 *
	 * @since	6.0.0
	 * @version	6.2.9
	 *
     * @return void
	 */
	public function enqueue(): void {
		global $_wp_current_template_content;
		$content	= get_post_field( 'post_content', get_the_ID() );

		$blocks_1   = parse_blocks( $content );
		$blocks_1 	= wp_list_pluck( _flatten_blocks( $blocks_1 ), 'blockName' );

		$blocks_2   = parse_blocks( $_wp_current_template_content );
		$blocks_2 	= wp_list_pluck( _flatten_blocks( $blocks_2 ), 'blockName' );

		$blocks     = array_unique( array_merge( $blocks_2, $blocks_1 ) );

		$should_load = function( $data ) use( $blocks, $content, $_wp_current_template_content ) {
			$condition = get_prop( $data, [ 'load' ], true );

			if( is_callable( $condition ) ) {
				$condition = call_user_func( $condition, $blocks, $content, $_wp_current_template_content );
			}

			return (bool) $condition;
		};

		foreach( $this->all( 'scripts' ) as $handle => $data ) {
			// Condition
			if( $should_load( $data ) === false ) {
				continue;
			}

			// Enqueue
			wp_enqueue_script( $handle );

			// Locale JS
			if( $locale = get_prop( $data, [ 'locale' ] ) ) {
				$locale_handle = lcfirst( join( '', array_map( 'ucfirst', explode( '-', $handle ) ) ) );
				$locale_handle = $handle === $this->make_handle() ? 'wecodeart' : $locale_handle;
				wp_localize_script( $handle, $locale_handle, $locale );
			}

			// Inline JS
			if( ! empty( $inline = self::get_inline( $data ) ) ) {
				wp_add_inline_script( $handle, $inline, get_prop( $data, [ 'where' ], 'after' ) );
			}
		}
		
		foreach( $this->all( 'styles' ) as $handle => $data ) {
			// Condition
			if( $should_load( $data ) === false ) {
				continue;
			}

			// Enqueue
			wp_enqueue_style( $handle );

			// RTL?
			if ( get_prop( $data, 'rtl' ) ) {
				wp_style_add_data( $handle, 'rtl', 'replace' );
			}

			// Inline CSS
			if( ! empty( $inline = self::get_inline( $data ) ) ) {
				wp_add_inline_style( $handle, wecodeart( 'styles' )::compress( $inline ) );
			}
		}
	}

	/**
     * Get inline code
     *
     * @param  array  $data
     *
     * @return string
     */
    public static function get_inline( array $data = [] ): string {
		$inline = get_prop( $data, [ 'inline' ], '' );
		
		if( str_starts_with( $inline, 'file:' ) ) {
			$paths 		= wecodeart_config( 'paths' );
			
			$file_url	= explode( 'file:', $inline );
			$file_path	= wp_normalize_path( str_replace( $paths['uri'], $paths['directory'], end( $file_url ) ) );

			$inline 	= file_exists( $file_path ) ? file_get_contents( $file_path ) : $inline;
		}

		return $inline;
    }

	/**
     * Removes asset from the container.
     *
     * @param  string  $key
     * @param  string  $type
     *
     * @return void
     */
    public function forget( string $key, string $type ): void {
		if( $type === 'scripts' ) {
			unset( self::$scripts[$key] );
		}

		if( $type === 'styles' ) {
			unset( self::$styles[$key] );
		}

		return;
    }

    /**
     * Get all of the assets for the application.
     *
     * @return array
     */
    public function all( string $type = 'all' ): array {
		if( $type === 'styles' ) {
			return self::$styles;
		}

		if( $type === 'scripts' ) {
			return self::$scripts;
		}

        return [
			'styles' 	=> self::$styles,
			'scripts' 	=> self::$scripts
		];
    }
}