<?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  Styles\Components
 * @copyright   Copyright (c) 2025, WeCodeArt Framework
 * @since		6.1.7
 * @version		6.5.2
 */

namespace WeCodeArt\Support\Styles;

defined( 'ABSPATH' ) || exit;

use WeCodeArt\Config\Interfaces\Configuration;
use WeCodeArt\Config\Traits\{ Asset, Singleton };
use function WeCodeArt\Functions\get_prop;
 
/**
 * Handles Components.
 */
class Components implements Configuration {

	use Singleton;
    use Asset;

    /**
	 * The CSS cache file.
	 *
	 * @var string
	 */
    const CACHE_FILE    = 'wp-components.css';
    const CACHE_KEY     = 'wecodeart/support/styles/components';

	/**
     * All of the configuration items.
     *
     * @var array
     */
    protected $items 	= [];

    /**
	 * The components to load
	 *
	 * @access 	public
	 * @var 	array
	 */
	protected $loaded  = [ 'backdrop' ];

    /**
	 * Send to Constructor
	 */
	public function init() {
        // Modules
		$this->register( 'close',       Components\Close::class     );
		$this->register( 'modal',       Components\Modal::class     );
		$this->register( 'toast',       Components\Toast::class     );
		$this->register( 'toggler',     Components\Toggler::class   );
		$this->register( 'lightbox',    Components\Lightbox::class  );
		$this->register( 'offcanvas',   Components\OffCanvas::class );
		$this->register( 'parallax',    Components\Parallax::class  );
		$this->register( 'backdrop',    Components\Backdrop::class  );
		$this->register( 'transition',  Components\Transition::class);

        \add_action( 'init',                                        [ $this, 'cache'        ], 95    );
        \add_action( 'wp_enqueue_scripts',                          [ $this, 'assets'       ], 20, 1 );
        \add_action( 'enqueue_block_assets',                        [ $this, 'editor_css'   ], 20, 1 );
		\add_filter( 'wecodeart/filter/gutenberg/settings/classes', [ $this, 'suggestions'  ], 20, 1 );
	}

    /**
     * Load.
     *
     * @param  string|array
     *
     * @return void
     */
    public function load( $key ) {
        return $this->loaded = array_merge( $this->loaded, (array) $key );
	}

    /**
	 * Generate cache.
	 *
	 * @return  void
	 */
	public function cache(): void {
		$filesystem = wecodeart( 'files' );
        $filesystem->set_folder( 'cache' );
        if( ! $filesystem->has_file( self::CACHE_FILE ) || false === get_transient( self::CACHE_KEY ) ) {
            $inline = '';
            foreach( $this->all() as $component ) {
                $inline .= $component::styles();
            }
			$filesystem->create_file( self::CACHE_FILE, wecodeart( 'styles' )::compress( $inline ) );
			set_transient( self::CACHE_KEY, true, 5 * MINUTE_IN_SECONDS );
		}
        $filesystem->set_folder( '' );
	}
    
    /**
	 * Enqueue Assets
     *
     * @return void
	 */
	public function assets(): void {
        if( empty( $this->loaded ) ) {
            return;
        }

		$inline_css = '';

        $queue = [];

		foreach( array_unique( $this->loaded ) as $component ) {
            // If we dont have component, move on.
            if( ! $this->has( $component ) ) {
                continue;
            }

            $queue[] = $component;

            // Merge deps.
            if( ! empty( $deps = $this->get( $component )::$deps ) ) {
				foreach( $deps as $dep ) {
					// Skip already loaded.
					if( in_array( $dep, $queue ) ) {
						continue;
					}

                    array_unshift( $queue, $dep );
				}
			}
        }
        
        if( empty( $queue ) ) {
            return;
        }
           
        foreach( array_unique( $queue ) as $component ) {
            $inline_css .= $this->get( $component )::styles();
        }

		if( empty( $inline_css ) ) {
            return;
        }

        wecodeart( 'assets' )->add_style( $this->make_handle(), [
            'inline' => $inline_css
        ] );
	}

    /**
	 * Load Utilities CSS on admin.
	 *
	 * @return  void
	 */
	public function editor_css(): void {
        if( ! is_admin() ) {
            return;
        }

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

        wp_enqueue_style(
			$this->make_handle(),
			$filesystem->get_file_url( self::CACHE_FILE, true ),
			[],
			wecodeart( 'version' )
		);
		
		$filesystem->set_folder( '' );
	}

    /**
	 * Add helper classes.
	 *
	 * @param 	array  	$args
	 *
	 * @return 	array 	Returns updated editors settings.
	 */
	public function suggestions( array $args ): array {
		$breakpoints	= wecodeart_json( [ 'settings', 'custom', 'breakpoints' ], [] );

		foreach( array_keys( $breakpoints ) as $breakpoint ) {
			$args[] = $breakpoint . ':wp-offcanvas--expand';
		}
		
		foreach( [ 'start', 'end', 'top', 'bottom'] as $side ) {
			$args[] = 'wp-offcanvas--' . $side;
		}

		return $args;
	}
	
	/**
     * Set a given integration value.
     *
     * @param  array|string  $key
     * @param  mixed   $value
     *
     * @return void
     */
    public function register( $key, $value = null ) {
        $this->set( $key, $value );
	}

    /**
     * Set a given configuration 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/styles/components/set/{$key}", $value );
        }
    }

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

    /**
     * Get the specified configuration 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/styles/components/set/{$key}", $this->items[$key] );
	}

    /**
     * Forget a given configuration value.
     *
     * @param string  $key
     *
     * @return void
     */
    public function forget( $key ) {
        unset( $this->items[$key] );
    }

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