<?php
/**
 * File Path: includes/class-mbs-front-assets.php
 *
 * Front-End Asset Enqueuer — My Book Showroom
 *
 * Registers and enqueues all front-end CSS and JS for MBS pages.
 * Assets are conditionally loaded only on pages that contain MBS content.
 *
 * Responsibilities:
 *   - wp_enqueue_scripts — CSS (mbs-front, RTL, PRO, PRO-RTL) and JS
 *     (mbs-front, mbs-layout-filter, mbs-layout-popup, mbs-format-tabs).
 *   - wp_head (priority 1) — blocking inline script that applies
 *     data-mbs-theme="dark" before first paint (FOUC prevention).
 *   - Inline CSS — admin-saved color token overrides and custom CSS.
 *
 * @package    My_Book_Showroom
 * @subpackage Includes
 * @since      1.0.0
 */

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

class MBS_Front_Assets {

	// ── Public API ─────────────────────────────────────────────────────────────

	/**
	 * Register the wp_enqueue_scripts hook.
	 *
	 * Called once from MBS_Plugin::init().
	 */
	public function register(): void {
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue' ) );
		// F-007 / RF-007: Dark mode head injection and analytics hooks are now
		// registered by MBS_Dark_Mode_Manager and MBS_Analytics_Manager respectively,
		// instantiated in MBS_Plugin::load_core_services().
	}

	/**
	 * Enqueue front-end assets only on pages that contain MBS content.
	 */
	public function enqueue(): void {
		$has_mbs_content = false;
		// UNREGFREE-13-17: separate flag for Gutenberg block pages. Block render
		// callbacks manage their own registration checks, so the global
		// mbs_is_registered() gate is bypassed when blocks are detected.
		$has_mbs_blocks  = false;

		if ( is_singular( MBS_POST_TYPE ) ) {
			$has_mbs_content = true;
		} elseif ( is_post_type_archive( MBS_POST_TYPE ) ) {
			$has_mbs_content = true;
		} elseif ( is_tax( array( MBS_TAX_AUTHOR, MBS_TAX_SERIES, MBS_TAX_GENRE, MBS_TAX_TAG, MBS_TAX_COLLECTION, MBS_TAX_UNIVERSE, MBS_TAX_THEME, MBS_TAX_CONTENT_WARNING, MBS_TAX_PUBLISHER, MBS_TAX_IMPRINT, MBS_TAX_CONTRIBUTOR ) ) ) {
			$has_mbs_content = true;
		} else {
			global $post;
			if ( isset( $post->post_content ) ) {
				// Shortcode detection (F-026-5) — V2-H-001: added mbs_search, mbs_author, mbs_author_directory.
				if ( has_shortcode( $post->post_content, 'mbs_books' )
					 || has_shortcode( $post->post_content, 'mbs_book' )
					 || has_shortcode( $post->post_content, 'mbs_esp_signup' )
					 || has_shortcode( $post->post_content, 'mbs_search' )
					 || has_shortcode( $post->post_content, 'mbs_author' )
					 || has_shortcode( $post->post_content, 'mbs_author_directory' ) ) {
					$has_mbs_content = true;
				}
				// UNREGFREE-13-17: detect Gutenberg blocks on arbitrary pages.
				// The catalog block intentionally works for keyless users; all
				// other block render callbacks enforce their own mbs_is_registered()
				// check internally. CSS must load regardless of registration tier.
				if ( str_contains( $post->post_content, '<!-- wp:mbs/' ) ) {
					$has_mbs_content = true;
					$has_mbs_blocks  = true;
				}
			}
		}

		if ( ! $has_mbs_content ) {
			return;
		}

		// Registration gate: MBS archive and shortcode pages require a registered
		// license. Block pages bypass this gate because each block render callback
		// enforces its own check (UNREGFREE-13-17). mbs_is_registered() gate is
		// preserved for all non-block MBS pages to maintain the existing behavior.
		if ( ! mbs_is_registered() && ! $has_mbs_blocks ) {
			return;
		}

		// DEV-001: Use filemtime() version when MBS_DEV_MODE is active so any
		// CSS change immediately busts the browser cache without a manual version bump.
		$css_ver = defined( 'MBS_DEV_MODE' ) && MBS_DEV_MODE
			? (string) filemtime( MBS_DIR . 'assets/css/mbs-front.css' )
			: MBS_VERSION;
		wp_enqueue_style( 'mbs-front', MBS_ASSETS_URL . 'css/mbs-front.css', array(), $css_ver );

		// Component stylesheets — split from mbs-front.css (Session 94).
		wp_enqueue_style( 'mbs-front-modal', MBS_ASSETS_URL . 'css/front/mbs-front-modal.css', array( 'mbs-front' ), $css_ver );
		wp_enqueue_style( 'mbs-front-term-list', MBS_ASSETS_URL . 'css/front/mbs-front-term-list.css', array( 'mbs-front' ), $css_ver );
		wp_enqueue_style( 'mbs-front-fse', MBS_ASSETS_URL . 'css/front/mbs-front-fse.css', array( 'mbs-front' ), $css_ver );
		wp_enqueue_style( 'mbs-front-landing', MBS_ASSETS_URL . 'css/front/mbs-front-landing.css', array( 'mbs-front' ), $css_ver );
		if ( class_exists( 'WooCommerce' ) ) {
			wp_enqueue_style( 'mbs-front-woocommerce', MBS_ASSETS_URL . 'css/front/mbs-front-woocommerce.css', array( 'mbs-front' ), $css_ver );
		}
		wp_enqueue_style( 'mbs-front-list-layout', MBS_ASSETS_URL . 'css/front/mbs-front-list-layout.css', array( 'mbs-front' ), $css_ver );
		wp_enqueue_style( 'mbs-front-buy-links', MBS_ASSETS_URL . 'css/front/mbs-front-buy-links.css', array( 'mbs-front' ), $css_ver );
		wp_enqueue_style( 'mbs-front-responsive', MBS_ASSETS_URL . 'css/front/mbs-front-responsive.css', array( 'mbs-front' ), $css_ver );
		wp_enqueue_style( 'mbs-front-power-badge', MBS_ASSETS_URL . 'css/front/mbs-front-power-badge.css', array( 'mbs-front' ), $css_ver );
		wp_enqueue_style( 'mbs-front-series-badge', MBS_ASSETS_URL . 'css/front/mbs-front-series-badge.css', array( 'mbs-front' ), $css_ver );
		wp_enqueue_style( 'mbs-front-coming-soon-badge', MBS_ASSETS_URL . 'css/front/mbs-front-coming-soon-badge.css', array( 'mbs-front' ), $css_ver );
		wp_enqueue_style( 'mbs-front-social-share', MBS_ASSETS_URL . 'css/front/mbs-front-social-share.css', array( 'mbs-front' ), $css_ver );
		wp_enqueue_style( 'mbs-front-signup', MBS_ASSETS_URL . 'css/front/mbs-front-signup.css', array( 'mbs-front' ), $css_ver );
		wp_enqueue_style( 'mbs-front-series-shelf', MBS_ASSETS_URL . 'css/front/mbs-front-series-shelf.css', array( 'mbs-front' ), $css_ver );
		// DISPLAY-1: Publication timeline CSS.
		wp_enqueue_style( 'mbs-front-timeline', MBS_ASSETS_URL . 'css/front/mbs-front-timeline.css', array( 'mbs-front' ), $css_ver );
		wp_enqueue_style( 'mbs-front-card-hover', MBS_ASSETS_URL . 'css/front/mbs-front-card-hover.css', array( 'mbs-front' ), $css_ver );
		wp_enqueue_style( 'mbs-front-categorization', MBS_ASSETS_URL . 'css/front/mbs-front-categorization.css', array( 'mbs-front' ), $css_ver );
		wp_enqueue_style( 'mbs-front-look-inside', MBS_ASSETS_URL . 'css/front/mbs-front-look-inside.css', array( 'mbs-front' ), $css_ver );
		wp_enqueue_style( 'mbs-front-hero',   MBS_ASSETS_URL . 'css/front/mbs-front-hero.css',   array( 'mbs-front' ), $css_ver );
		if ( is_singular( MBS_POST_TYPE ) ) {
			wp_enqueue_style( 'mbs-front-single', MBS_ASSETS_URL . 'css/front/mbs-front-single.css', array( 'mbs-front' ), $css_ver );
		}
		// INSIGHTS-3: Press Kit public download button styles.
		wp_enqueue_style( 'mbs-front-press-kit', MBS_ASSETS_URL . 'css/front/mbs-front-press-kit.css', array( 'mbs-front' ), $css_ver );
		// F-007: Dark mode token overrides — flat selectors, all themes. Enqueued
		// unconditionally because per-post overrides can activate dark mode
		// independently of the global toggle.
		wp_enqueue_style( 'mbs-front-dark', MBS_ASSETS_URL . 'css/front/mbs-front-dark.css', array( 'mbs-front' ), $css_ver );

		// GC1-6 (I-014): RTL layout override — only loaded when the site locale is RTL.
		if ( is_rtl() ) {
			wp_enqueue_style( 'mbs-front-rtl', MBS_ASSETS_URL . 'css/mbs-front-rtl.css', array( 'mbs-front' ), MBS_VERSION );
		}

		// PRO-tier layout and Author Hero styles — FREE visitors never receive this file.
		if ( mbs_is_pro() ) {
			$pro_css_ver = defined( 'MBS_DEV_MODE' ) && MBS_DEV_MODE
				? (string) filemtime( MBS_DIR . 'assets/css/mbs-front-pro.css' )
				: MBS_VERSION;
			wp_enqueue_style( 'mbs-front-pro', MBS_ASSETS_URL . 'css/mbs-front-pro.css', array( 'mbs-front' ), $pro_css_ver );

			// PRO component stylesheets — split from mbs-front-pro.css (Session 94).
			wp_enqueue_style( 'mbs-front-pro-author-hero', MBS_ASSETS_URL . 'css/front/mbs-front-pro-author-hero.css', array( 'mbs-front-pro' ), $pro_css_ver );
			wp_enqueue_style( 'mbs-front-pro-series-archive', MBS_ASSETS_URL . 'css/front/mbs-front-pro-series-archive.css', array( 'mbs-front-pro' ), $pro_css_ver );
			wp_enqueue_style( 'mbs-front-pro-collection-archive', MBS_ASSETS_URL . 'css/front/mbs-front-pro-collection-archive.css', array( 'mbs-front-pro' ), $pro_css_ver );
			wp_enqueue_style( 'mbs-front-pro-universe-archive', MBS_ASSETS_URL . 'css/front/mbs-front-pro-universe-archive.css', array( 'mbs-front-pro' ), $pro_css_ver );
			wp_enqueue_style( 'mbs-front-pro-slider', MBS_ASSETS_URL . 'css/front/mbs-front-pro-slider.css', array( 'mbs-front-pro' ), $pro_css_ver );
			wp_enqueue_style( 'mbs-front-pro-flip', MBS_ASSETS_URL . 'css/front/mbs-front-pro-flip.css', array( 'mbs-front-pro' ), $pro_css_ver );
			wp_enqueue_style( 'mbs-front-pro-author-directory', MBS_ASSETS_URL . 'css/front/mbs-front-pro-author-directory.css', array( 'mbs-front-pro' ), $pro_css_ver );
			wp_enqueue_style( 'mbs-front-pro-signup', MBS_ASSETS_URL . 'css/front/mbs-front-pro-signup.css', array( 'mbs-front-pro' ), $pro_css_ver );

			// F-026-5: Reader signup widget JS -- only when widget is enabled.
			if ( '1' === mbs_get_setting( 'email', 'widget_enabled', '0' ) ) {
				wp_enqueue_script(
					'mbs-esp-signup',
					MBS_ASSETS_URL . 'js/mbs-esp-signup.js',
					array( 'jquery', 'wp-i18n' ),
					MBS_VERSION,
					true
				);
				wp_set_script_translations( 'mbs-esp-signup', 'my-book-showroom', MBS_DIR . 'languages' );
				wp_localize_script( 'mbs-esp-signup', 'MBS_ESPSignup', array(
					'ajaxurl' => admin_url( 'admin-ajax.php' ),
				) );
			}

			// GC1-6 (I-014): PRO RTL override — only loaded when the site locale is RTL.
			if ( is_rtl() ) {
				wp_enqueue_style( 'mbs-front-pro-rtl', MBS_ASSETS_URL . 'css/mbs-front-pro-rtl.css', array( 'mbs-front-pro' ), MBS_VERSION );
			}

			// Story 9-8 / JS-001: Filter + Popup layout scripts are archive-only.
			// They serve no purpose on a single-book page and add unnecessary overhead.
			if ( ! is_singular( MBS_POST_TYPE ) ) {
				// Slider layout prev/next button handler — archive-only (same scope as filter/popup).
				wp_enqueue_script( 'mbs-layout-slider', MBS_ASSETS_URL . 'js/mbs-layout-slider.js', array(), MBS_VERSION, true );

				// Story 9-8: Filter layout client-side filtering.
				wp_enqueue_script( 'mbs-layout-filter', MBS_ASSETS_URL . 'js/mbs-layout-filter.js', array( 'jquery' ), MBS_VERSION, true );

				// REF-36 / Story 9-9: Popup layout modal interaction.
				// GC1-5 (I-013): wp-i18n added as dep; wp_set_script_translations() registered.
				wp_enqueue_script( 'mbs-layout-popup', MBS_ASSETS_URL . 'js/mbs-layout-popup.js', array( 'jquery', 'wp-i18n' ), MBS_VERSION, true );
				wp_set_script_translations( 'mbs-layout-popup', 'my-book-showroom', MBS_DIR . 'languages' );
			}
		}

		// GC1-5 (I-001/I-013): wp-i18n added as dep; wp_set_script_translations() registered.
		// RF-010: mbs-front.js split into per-module files (Sprint RF-4).
		// Core namespace and module registry -- always loaded on MBS pages.
		wp_enqueue_script( 'mbs-front-core', MBS_ASSETS_URL . 'js/mbs-front-core.js', array( 'jquery', 'wp-i18n' ), MBS_VERSION, true );
		wp_set_script_translations( 'mbs-front-core', 'my-book-showroom', MBS_DIR . 'languages' );

		// Always-loaded modules.
		wp_enqueue_script( 'mbs-front-order-now',    MBS_ASSETS_URL . 'js/mbs-front-order-now.js',    array( 'mbs-front-core' ), MBS_VERSION, true );
		wp_set_script_translations( 'mbs-front-order-now', 'my-book-showroom', MBS_DIR . 'languages' );
		wp_enqueue_script( 'mbs-front-buy-links',    MBS_ASSETS_URL . 'js/mbs-front-buy-links.js',    array( 'mbs-front-core' ), MBS_VERSION, true );
		wp_set_script_translations( 'mbs-front-buy-links', 'my-book-showroom', MBS_DIR . 'languages' );
		// V2-H-002: mbs-front-search.js is only needed on pages that use [mbs_search] shortcode
		// or mbs/search block (SRCH-001). Taxonomy/archive pages don't embed either, so this guard is safe.
		global $post;
		if ( isset( $post->post_content ) && ( has_shortcode( $post->post_content, 'mbs_search' ) || has_block( 'mbs/search', $post ) ) ) {
			wp_enqueue_script( 'mbs-front-search', MBS_ASSETS_URL . 'js/mbs-front-search.js', array( 'mbs-front-core' ), MBS_VERSION, true );
		}
		if ( is_singular( MBS_POST_TYPE ) ) {
			wp_enqueue_script( 'mbs-front-cover-video',  MBS_ASSETS_URL . 'js/mbs-front-cover-video.js',  array( 'mbs-front-core' ), MBS_VERSION, true );
		}

		// WooCommerce price update -- only on WooCommerce-active installs.
		if ( class_exists( 'WooCommerce' ) ) {
			wp_enqueue_script( 'mbs-front-wc', MBS_ASSETS_URL . 'js/mbs-front-wc.js', array( 'mbs-front-core' ), MBS_VERSION, true );
		}

		// Look Inside read-more -- only on singular book pages that have look-inside content.
		if ( is_singular( MBS_POST_TYPE ) && get_post_meta( get_the_ID(), 'mbs_look_inside_text', true ) ) {
			wp_enqueue_script( 'mbs-front-look-inside', MBS_ASSETS_URL . 'js/mbs-front-look-inside.js', array( 'mbs-front-core' ), MBS_VERSION, true );
		}

		// Format selector / tab switching — single book pages only.
		if ( is_singular( MBS_POST_TYPE ) ) {
			wp_enqueue_script( 'mbs-format-tabs', MBS_ASSETS_URL . 'js/mbs-format-tabs.js', array( 'jquery' ), MBS_VERSION, true );

			// Story 9-7: Localize review AJAX data onto the already-enqueued mbs-front handle.
			// Scoped to singular book pages only — the form only renders there.
			wp_localize_script( 'mbs-front-core', 'MBS_ReviewAjax', array(
				'nonce'   => wp_create_nonce( 'mbs_submit_review' ),
				'ajaxurl' => admin_url( 'admin-ajax.php' ),
				'postId'  => get_the_ID(),
			) );
		}

		// Scoped to MBS pages only (deliberate — matches other appearance settings).
		// A-009: wp_strip_all_tags() applied before output. wp_add_inline_style()
		// does not sanitize; an admin with manage_options could inject arbitrary CSS.
		$custom_css = get_option( 'mbs_setting_appearance_custom_css', '' );
		if ( ! empty( $custom_css ) ) {
			wp_add_inline_style( 'mbs-front', wp_strip_all_tags( $custom_css ) );
		}

		// F-007: Inject admin-saved color tokens as CSS custom property overrides on .mbs-wrapper.
		$this->output_color_vars();

		// F-002: Inject admin-saved layout geometry vars (gap, columns, card radius).
		$this->output_layout_vars();

			}

	/**
	 * Output a blocking inline script in <head> that applies data-mbs-theme="dark"
	 * to the <html> element before first paint. Prevents flash of light mode when
	 * the admin has enabled dark mode. Hooked to wp_head at priority 1 via register().
	 *
	 * F-007 S3: Per-post override logic —
	 *   mbs_theme_override = 'light' → suppress dark even if global setting is on.
	 *   mbs_theme_override = 'dark'  → force dark even if global setting is off.
	 *   mbs_theme_override = ''      → Inherit: follow the global setting.
	 * On non-singular pages (archives, shortcode pages) $override stays '' and the
	 * global setting governs — correct behavior.
	 * Emits nothing when neither global dark mode nor a per-post override is active.
	 *
	 * @return void
	 */

	// RF-007: inject_analytics_head() and analytics_admin_notice() have been
	// extracted to MBS_Analytics_Manager in includes/helpers/.

	// ── Private helpers ────────────────────────────────────────────────────────

	/**
	 * Build and inject the admin-saved color token overrides as a CSS custom
	 * property block on .mbs-wrapper. Runs after mbs-front.css is enqueued so
	 * the inline block appends to that handle in the style queue.
	 *
	 * F-007 / mbs_output_color_vars: First implementation.
	 * - FREE tier: 4 tokens (accent, button_bg, button_text, link).
	 * - PRO tier: additional 16 structural / badge / card tokens.
	 * Values are already sanitized at save time via MBS_Color_Helper::sanitize().
	 * wp_strip_all_tags() applied to the full CSS string before output (A-009).
	 *
	 * Token → CSS custom property mapping (D-2 canonical names):
	 * See MBS_Tab_Appearance::FREE_DEFAULTS and render_pro_colors() for defaults.
	 *
	 * @return void
	 */
	private function output_color_vars(): void {
		// FREE tokens (4).
		$colors = array(
			'accent'      => mbs_get_setting( 'appearance', 'accent',      '#4AABB8' ),
			'button-bg'   => mbs_get_setting( 'appearance', 'button_bg',   '#2C3E6B' ),
			'button-text' => mbs_get_setting( 'appearance', 'button_text', '#FFFFFF' ),
			'link'        => mbs_get_setting( 'appearance', 'link',        '#4AABB8' ),
		);

		if ( mbs_is_pro() ) {
			// PRO tokens (16).
			$pro_colors = array(
				'navy'           => mbs_get_setting( 'appearance', 'navy',           '#2C3E6B' ),
				'navy-dark'      => mbs_get_setting( 'appearance', 'navy_dark',      '#1A2B50' ),
				'lavender'       => mbs_get_setting( 'appearance', 'lavender',       '#C8B4D4' ),
				'teal-pale'      => mbs_get_setting( 'appearance', 'teal_pale',      '#D4EEF1' ),
				'lavender-pale'  => mbs_get_setting( 'appearance', 'lavender_pale',  '#EDE8F4' ),
				'beige'          => mbs_get_setting( 'appearance', 'beige',          '#F4F0E8' ),
				'slate'          => mbs_get_setting( 'appearance', 'slate',          '#5A6472' ),
				'mist'           => mbs_get_setting( 'appearance', 'mist',           '#9AABBA' ),
				'pro-bg'           => mbs_get_setting( 'appearance', 'pro_bg',           '#EDE8F4' ),
				'pro-text'         => mbs_get_setting( 'appearance', 'pro_text',         '#5A3A72' ),
				'coming-soon-bg'   => mbs_get_setting( 'appearance', 'coming_soon_bg',   '#F59E0B' ),
				'coming-soon-text' => mbs_get_setting( 'appearance', 'coming_soon_text', '#FFFFFF' ),
				'card-bg'        => mbs_get_setting( 'appearance', 'card_bg',        '#FFFFFF' ),
				'border'         => mbs_get_setting( 'appearance', 'border',         '#E0D8C8' ),
				'watermark-text' => mbs_get_setting( 'appearance', 'watermark_text', '#9AABBA' ),
				'star'           => mbs_get_setting( 'appearance', 'star',           '#F5A623' ),
			);
			$colors = array_merge( $colors, $pro_colors );
		}

		$css = ':root .mbs-wrapper {';
		foreach ( $colors as $css_key => $value ) {
			$safe_value = MBS_Color_Helper::sanitize( $value );
			$css       .= '--mbs-' . sanitize_key( $css_key ) . ': ' . esc_attr( $safe_value ) . '; ';
		}
		$css .= '}';

		// A-009: strip all tags before registering the inline style block.
		wp_add_inline_style( 'mbs-front', wp_strip_all_tags( $css ) );
	}

	/**
	 * Build and inject admin-saved layout geometry vars as a CSS custom
	 * property override block on .mbs-wrapper. Appends to the mbs-front
	 * style handle so the block always follows mbs-front.css in the queue.
	 *
	 * F-002: Layout customization (gap, columns, card radius).
	 * - FREE tier: gap preset only.
	 * - PRO tier: gap + column count + radius preset.
	 * Only outputs a <style> block when at least one value is explicitly saved.
	 * When unset, the CSS var() fallbacks in mbs-front.css govern — zero regression.
	 *
	 * @return void
	 */
	private function output_layout_vars(): void {
		$gap_map = array(
			'compact'     => '0.5rem',
			'comfortable' => '1rem',
			'spacious'    => '1.75rem',
		);
		$radius_map = array(
			'square'  => '0px',
			'slight'  => '4px',
			'rounded' => '12px',
		);

		$gap_slug = mbs_get_setting( 'appearance', 'gap', '' );
		$columns  = absint( mbs_get_setting( 'appearance', 'columns', 0 ) );
		$rad_slug = mbs_is_pro() ? mbs_get_setting( 'appearance', 'radius', '' ) : '';

		$vars = array();

		if ( isset( $gap_map[ $gap_slug ] ) ) {
			$vars['--mbs-layout-gap'] = $gap_map[ $gap_slug ];
		}
		if ( mbs_is_pro() && $columns >= 1 && $columns <= 6 ) {
			$vars['--mbs-columns'] = (string) $columns;
		}
		if ( isset( $radius_map[ $rad_slug ] ) ) {
			$vars['--mbs-card-radius'] = $radius_map[ $rad_slug ];
		}

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

		$css = ':root .mbs-wrapper {';
		foreach ( $vars as $prop => $value ) {
			$css .= esc_attr( $prop ) . ': ' . esc_attr( $value ) . '; ';
		}
		$css .= '}';

		wp_add_inline_style( 'mbs-front', wp_strip_all_tags( $css ) );
	}
}
