<?php
/**
 * Main plugin bootstrap.
 *
 * @package CraftAddonsForWPBakery
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class CAFW_Plugin
 *
 * Singleton that boots the plugin, wires hooks, and loads addon elements.
 */
final class CAFW_Plugin {

	/**
	 * Single instance.
	 *
	 * @var CAFW_Plugin|null
	 */
	private static $instance = null;

	/**
	 * Element loader.
	 *
	 * @var CAFW_Loader
	 */
	private $loader;

	/**
	 * Admin panel.
	 *
	 * @var CAFW_Admin
	 */
	private $admin;

	/**
	 * Responsive Visibility settings page.
	 *
	 * @var CAFW_Responsive_Settings
	 */
	private $responsive_settings;

	/**
	 * Retrieve the singleton instance.
	 *
	 * @return CAFW_Plugin
	 */
	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Constructor. Private to enforce singleton.
	 */
	private function __construct() {
		$this->loader = new CAFW_Loader();

		$responsive = CAFW_Modules::is_enabled( 'responsive-visibility' );
		if ( $responsive ) {
			CAFW_Responsive::init();
		}

		if ( CAFW_Modules::is_enabled( 'dynamic-content' ) ) {
			CAFW_Dynamic::init();
		}

		if ( is_admin() ) {
			$this->admin = new CAFW_Admin( $this->loader );
			$this->admin->init();
			CAFW_Pricing::init();
			CAFW_Preview::init();

			if ( $responsive ) {
				$this->responsive_settings = new CAFW_Responsive_Settings();
				$this->responsive_settings->init();
			}
		}

		$this->hooks();
	}

	/**
	 * The element loader (also used by the backend-preview AJAX endpoint).
	 *
	 * @return CAFW_Loader
	 */
	public function get_loader() {
		return $this->loader;
	}

	/**
	 * Register WordPress hooks.
	 *
	 * @return void
	 */
	private function hooks() {
		add_action( 'vc_before_init', array( $this, 'register_elements' ) );
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ) );
		add_action( 'admin_notices', array( $this, 'maybe_show_wpbakery_notice' ) );
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_editor_icons' ) );
		add_action( 'vc_frontend_editor_enqueue_js_css', array( $this, 'enqueue_editor_icons_front' ) );
	}

	/**
	 * Enqueue the element icon styles in the backend WPBakery editor.
	 *
	 * @param string $hook Current admin page hook.
	 * @return void
	 */
	public function enqueue_editor_icons( $hook ) {
		if ( ! in_array( $hook, array( 'post.php', 'post-new.php' ), true ) ) {
			return;
		}
		$this->enqueue_editor_icons_front();
	}

	/**
	 * Version string for an asset: the plugin version plus the file's mtime,
	 * so browsers re-fetch a changed file immediately instead of serving a
	 * stale cached copy.
	 *
	 * @param string $rel Asset path relative to the plugin root.
	 * @return string
	 */
	public static function asset_ver( $rel ) {
		$file = CAFW_PATH . $rel;
		$time = is_readable( $file ) ? filemtime( $file ) : false;
		return $time ? CAFW_VERSION . '.' . $time : CAFW_VERSION;
	}

	/**
	 * Enqueue the element icon styles (shared by both editor contexts).
	 *
	 * @return void
	 */
	public function enqueue_editor_icons_front() {
		wp_enqueue_style(
			'cafw-editor-icons',
			CAFW_URL . 'admin/css/cafw-editor-icons.css',
			array(),
			self::asset_ver( 'admin/css/cafw-editor-icons.css' )
		);

		// Hide toggled-off elements from the "Add Element" panel (they stay
		// registered so existing content still renders; they just can't be added
		// anew). WPBakery tags each panel button with data-element="<base>".
		$disabled_tags = $this->loader->disabled_editor_tags();
		if ( ! empty( $disabled_tags ) ) {
			$selectors = array();
			foreach ( $disabled_tags as $tag ) {
				$selectors[] = '#vc_ui-panel-add-element [data-element="' . $tag . '"]';
			}
			wp_add_inline_style( 'cafw-editor-icons', implode( ',', $selectors ) . '{display:none!important}' );
		}

		// The element styles too, so the backend-editor live previews look
		// like the real thing (all rules are .cafw-* scoped).
		wp_enqueue_style(
			'cafw-elements',
			CAFW_URL . 'assets/css/cafw-elements.css',
			array(),
			self::asset_ver( 'assets/css/cafw-elements.css' )
		);

		wp_enqueue_script(
			'cafw-editor',
			CAFW_URL . 'admin/js/cafw-editor.js',
			array( 'jquery' ),
			self::asset_ver( 'admin/js/cafw-editor.js' ),
			true
		);

		wp_localize_script(
			'cafw-editor',
			'cafwEditor',
			array(
				'ajaxUrl'     => admin_url( 'admin-ajax.php' ),
				'nonce'       => wp_create_nonce( 'cafw_preview' ),
				// Backend-editor live preview is off by default: our elements show
				// as WPBakery's standard icon + name block, like the native ones.
				// A site can opt back in per shortcode via the cafw_preview_tags filter.
				'previewTags' => apply_filters( 'cafw_preview_tags', array() ),
			)
		);
	}

	/**
	 * Check whether WPBakery Page Builder is active.
	 *
	 * @return bool
	 */
	public function is_wpbakery_active() {
		return function_exists( 'vc_map' ) && class_exists( 'WPBakeryShortCode' );
	}

	/**
	 * Register all enabled addon elements with WPBakery.
	 *
	 * @return void
	 */
	public function register_elements() {
		if ( ! $this->is_wpbakery_active() ) {
			return;
		}
		CAFW_Params::register();
		$this->loader->register_enabled();
	}

	/**
	 * Enqueue frontend assets.
	 *
	 * @return void
	 */
	public function enqueue_assets() {
		wp_enqueue_style(
			'cafw-elements',
			CAFW_URL . 'assets/css/cafw-elements.css',
			array(),
			self::asset_ver( 'assets/css/cafw-elements.css' )
		);

		// Inside the WPBakery inline editor the page renders in an iframe
		// (vc_inline-frame) where the element controls and edit panels actually
		// live. The frontend-editor enqueue hook only reaches the parent editor
		// chrome, so load our editor styles/JS (toolbar recolour, field
		// alignment, element icons) here too - otherwise the Flip Container
		// toolbar stays orange and paired fields don't line up in this editor.
		if ( function_exists( 'vc_is_inline' ) && vc_is_inline() ) {
			$this->enqueue_editor_icons_front();

			wp_enqueue_script(
				'cafw-flip-editor',
				CAFW_URL . 'admin/js/cafw-flip-editor.js',
				array(),
				self::asset_ver( 'admin/js/cafw-flip-editor.js' ),
				true
			);
		}

		wp_register_script(
			'cafw-counter',
			CAFW_URL . 'assets/js/cafw-counter.js',
			array(),
			self::asset_ver( 'assets/js/cafw-counter.js' ),
			true
		);

		wp_register_script(
			'cafw-flip',
			CAFW_URL . 'assets/js/cafw-flip.js',
			array(),
			self::asset_ver( 'assets/js/cafw-flip.js' ),
			true
		);
	}

	/**
	 * Show an admin notice if WPBakery is not active.
	 *
	 * @return void
	 */
	public function maybe_show_wpbakery_notice() {
		if ( $this->is_wpbakery_active() || ! current_user_can( 'activate_plugins' ) ) {
			return;
		}
		printf(
			'<div class="notice notice-warning"><p>%s</p></div>',
			esc_html__( 'Craft Addons requires the WPBakery Page Builder plugin to be installed and active.', 'craft-addons-for-wpbakery' )
		);
	}
}
