<?php
/**
 * Manages SpectraPro extensions and their assets.
 *
 * @package SpectraPro
 * @since 2.0.0-beta.1
 */

namespace SpectraPro;

use Spectra\Traits\Singleton;
use SpectraPro\Extensions\GlobalStyles;
use SpectraPro\Extensions\Countdown;
use SpectraPro\Extensions\Modal;
use SpectraPro\Extensions\PopupBuilder;
use SpectraPro\Extensions\SliderExtension;
use SpectraPro\Extensions\DynamicContent;
use SpectraPro\Extensions\ResponsiveControls;

defined( 'ABSPATH' ) || exit;

/**
 * Class to manage SpectraPro Extensions.
 *
 * @since 2.0.0-beta.1
 */
class ExtensionManager {

	use Singleton;

	/**
	 * An array of folder names of extensions that require a stylesheet.
	 *
	 * @since 2.0.0-beta.1
	 * 
	 * @var array
	 */
	private static $requires_styles = array(
		'global-styles',
	);

	/**
	 * Initializes the extension manager by registering all extensions.
	 *
	 * @since 2.0.0-beta.1
	 * 
	 * @return void
	 */
	public function init() {
		$this->init_extensions();

		add_action( 'enqueue_block_editor_assets', array( $this, 'register_extensions' ) );
	}

	/**
	 * Initializes all extensions by calling their init() method.
	 *
	 * This method triggers the initialization of all registered extensions
	 * when the extension manager starts.
	 *
	 * @since 2.0.0-beta.1
	 * 
	 * @return void
	 */
	public function init_extensions() {     
		// Initialize the SliderExtension for handling slider functionality in the Spectra plugin.
		if ( class_exists( SliderExtension::class ) ) {
			SliderExtension::instance()->init();
		}

		// Initialize the GlobalStyles system for Spectra Pro.
		if ( class_exists( GlobalStyles::class ) ) {
			( GlobalStyles::instance() )->init();
		}

		// Initialize the DynamicContent for handling dynamic content.
		if ( class_exists( DynamicContent::class ) ) {
			( DynamicContent::instance() )->init();
		}
		
		// Initialize the Countdown extension.
		if ( class_exists( Countdown::class ) ) {
			Countdown::instance()->init();
		}

		// Initialize the ModalExtension for handling modal functionality in the Spectra plugin.
		if ( class_exists( Modal::class ) ) {
			Modal::instance()->init();
		}

		// Initialize the PopupBuilderExtension for handling Popup Builder functionality in the Spectra plugin.
		if ( class_exists( PopupBuilder::class ) ) {
			PopupBuilder::instance()->init();
		}

		// Initialize the responsive controls extension.
		if ( class_exists( ResponsiveControls::class ) ) {
			ResponsiveControls::instance()->init();
		}
	}

	/**
	 * Enqueues all extensions' editor assets.
	 *
	 * This method scans the 'build/extensions/' directory for subdirectories containing
	 * an 'index.asset.php' file and calls enqueue_editor_extension_assets() for each.
	 *
	 * @since 2.0.0-beta.1
	 * 
	 * @return void
	 */
	public function register_extensions() {
		// Extensions directory.
		$extensions_dir = SPECTRA_PRO_2_DIR . 'build/extensions/';

		// Check if extensions directory exists and is readable.
		if ( ! is_dir( $extensions_dir ) || ! is_readable( $extensions_dir ) ) {
			return;
		}

		// Get all extension files.
		$extension_files = glob( $extensions_dir . '*/index.asset.php' );

		// If no extension files found, return.
		if ( empty( $extension_files ) ) {
			return;
		}

		// Enqueue editor assets for each extension.
		foreach ( $extension_files as $extension_file ) {
			$this->enqueue_editor_extension_assets( $extension_file );
		}
	}

	/**
	 * Enqueues editor assets for a given extension.
	 *
	 * @since 2.0.0-beta.1
	 *
	 * @param string $extension_file Path to the extension's asset file.
	 * @return void
	 */
	private function enqueue_editor_extension_assets( $extension_file ) {
		// Check if extension file exists if not exist, return.
		if ( ! file_exists( $extension_file ) ) {
			return;
		}

		// Get extension directory.
		$extension_dir = dirname( $extension_file );
		// Get extension folder name.
		$folder_name = basename( $extension_dir );
		// Extension handle name.
		$handle = "spectra-pro-2-extension-{$folder_name}-editor";
		// Extension script URL.
		$script_url = trailingslashit( SPECTRA_PRO_2_URL ) . "build/extensions/{$folder_name}/index.js";
		// Extension script path.
		$script_path = trailingslashit( SPECTRA_PRO_2_DIR ) . "build/extensions/{$folder_name}/index.js";

		// Check if extension script exists if not exist, return.
		if ( ! file_exists( $script_path ) ) {
			return;
		}

		// Load the asset file generated by Webpack.
		$asset_file = include_once $extension_file;

		// Enqueue editor assets.
		wp_enqueue_script(
			$handle,
			$script_url,
			$asset_file['dependencies'] ?? array(),
			$asset_file['version'] ?? SPECTRA_PRO_VER,
			true
		);

		if ( in_array( $folder_name, self::$requires_styles ) ) {
			// Extension script URL.
			$style_url = trailingslashit( SPECTRA_PRO_2_URL ) . "build/extensions/{$folder_name}/index.css";
			// Extension script path.
			$style_path = trailingslashit( SPECTRA_PRO_2_DIR ) . "build/extensions/{$folder_name}/index.css";

			if ( file_exists( $style_path ) ) {
				wp_enqueue_style(
					$handle,
					$style_url,
					array(),
					SPECTRA_PRO_VER
				);
			}
		}

		/**
		 * Fires after enqueuing the editor assets for the given extension.
		 *
		 * The dynamic portion of the filter name is the extension folder name.
		 *
		 * @since 2.0.0-beta.1
		 * 
		 * @param string $handle The handle of the current enqueued script.
		 * @param string $folder_name Extension folder name.
		 * @param array  $asset_file  Asset file data.
		 */
		do_action( 'spectra_pro_2_extensions_editor_assets', $handle, $folder_name, $asset_file );
	}
}
