<?php

defined( 'ABSPATH' ) || exit;

/**
 * YouTube Block module.
 *
 * Provides:
 *  - A dynamic Gutenberg block `bw-dev/youtube` that pulls a YouTube URL
 *    from an ACF field on the current post and renders a responsive 16:9
 *    iframe. Falls back to the post's featured image when no video is set.
 *  - A `[bw_dev_youtube]` shortcode with identical output for classic-editor
 *    contexts.
 *  - A backwards-compat `[bw_youtube]` alias that is registered ONLY when
 *    the legacy `bw-youtube-embed` plugin isn't active — avoids a shortcode
 *    collision during side-by-side migration.
 *
 * Per-block override: the block exposes an `acfField` attribute so each
 * insertion can target a different ACF field. Empty = use the global default
 * from this module's settings tab (default `youtube_link`).
 *
 * @package BW_Dev
 */

class BW_Dev_Module_Youtube implements BW_Dev_Module_Interface {

	const DEFAULT_FIELD = 'youtube_link';

	public function slug(): string {
		return 'youtube';
	}

	public function label(): string {
		return __( 'YouTube Block', 'bw-dev' );
	}

	public function group(): string {
		return 'blocks';
	}

	public function default_settings(): array {
		return array( 'acf_field' => self::DEFAULT_FIELD );
	}

	public function sanitize( array $data ): array {
		$field = isset( $data['acf_field'] ) ? sanitize_key( wp_unslash( (string) $data['acf_field'] ) ) : '';
		return array( 'acf_field' => '' !== $field ? $field : self::DEFAULT_FIELD );
	}

	/**
	 * Static accessor used by `blocks/youtube/render.php` (which doesn't
	 * have a $this in scope) and the shortcode handler. Falls back to the
	 * built-in default if the setting is empty.
	 */
	public static function get_default_field_name(): string {
		$value = (string) bw_dev()->settings()->get( 'youtube', 'acf_field', self::DEFAULT_FIELD );
		return '' !== $value ? $value : self::DEFAULT_FIELD;
	}

	/**
	 * Extract a YouTube video ID from any of the common URL shapes:
	 *   - https://www.youtube.com/watch?v=ID
	 *   - https://youtu.be/ID
	 *   - https://www.youtube.com/embed/ID
	 *   - https://www.youtube.com/shorts/ID
	 *
	 * The capture group is restricted to YouTube's actual ID character set
	 * ([A-Za-z0-9_-]) so injected HTML in a malformed URL can never reach
	 * the embed URL we build downstream.
	 *
	 * Returns the extracted ID or an empty string.
	 */
	public static function extract_video_id( string $url ): string {
		if ( '' === $url ) {
			return '';
		}
		if ( preg_match( '#(?:youtu\.be/|youtube\.com/(?:watch\?v=|embed/|shorts/))([A-Za-z0-9_-]+)#i', $url, $matches ) ) {
			return $matches[1];
		}
		return '';
	}

	public function register(): void {
		add_action( 'init', array( $this, 'register_block' ) );
		add_action( 'init', array( $this, 'register_shortcodes' ) );
		add_action( 'enqueue_block_editor_assets', array( $this, 'localize_editor_data' ) );
		add_action( 'wp_enqueue_scripts', array( $this, 'maybe_enqueue_shortcode_style' ) );
	}

	public function register_block(): void {
		register_block_type( BW_DEV_DIR . 'blocks/youtube' );
	}

	public function register_shortcodes(): void {
		add_shortcode( 'bw_dev_youtube', array( $this, 'render_shortcode' ) );

		// Backwards-compat alias for content authored against the legacy
		// `bw-youtube-embed` plugin. Skipped while that plugin is still
		// active (it registers the same shortcode at the same hook), so
		// each owns its handler until the user manually deactivates.
		if ( ! function_exists( 'bw_youtube_shortcode_handler' ) ) {
			add_shortcode( 'bw_youtube', array( $this, 'render_shortcode' ) );
		}
	}

	public function render_shortcode( $atts ): string {
		unset( $atts ); // intentional: shortcode takes no attributes today.
		$post_id     = get_the_ID();
		$field_name  = self::get_default_field_name();
		$youtube_url = ( function_exists( 'get_field' ) && $field_name )
			? get_field( $field_name, $post_id )
			: '';

		$video_id = self::extract_video_id( (string) $youtube_url );

		if ( $video_id ) {
			$embed_url = 'https://www.youtube.com/embed/' . rawurlencode( $video_id );
			return sprintf(
				'<div class="bw-dev-youtube-block"><div class="bw-dev-youtube-block__inner"><iframe src="%s" title="%s" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen loading="lazy"></iframe></div></div>',
				esc_url( $embed_url ),
				esc_attr__( 'YouTube video player', 'bw-dev' )
			);
		}

		if ( has_post_thumbnail( $post_id ) ) {
			$img = get_the_post_thumbnail( $post_id, 'large', array( 'class' => 'bw-dev-youtube-block__featured-img' ) );
			return '<div class="bw-dev-youtube-block bw-dev-youtube-block--fallback-image"><div class="bw-dev-youtube-block__inner">' . $img . '</div></div>';
		}

		return '';
	}

	/**
	 * Expose the global default ACF field name to the block editor so the
	 * InspectorControls can show it as the placeholder/help text.
	 */
	public function localize_editor_data(): void {
		$handle = generate_block_asset_handle( 'bw-dev/youtube', 'editorScript' );
		if ( ! wp_script_is( $handle, 'registered' ) ) {
			return;
		}
		wp_localize_script(
			$handle,
			'bwDevYouTube',
			array(
				'defaultField' => self::get_default_field_name(),
			)
		);
	}

	/**
	 * The block bundle's style.css auto-enqueues whenever the block renders.
	 * For posts using only the [bw_dev_youtube] shortcode (no block), we
	 * have to enqueue it ourselves so the 16:9 wrapper renders correctly.
	 */
	public function maybe_enqueue_shortcode_style(): void {
		if ( ! is_singular() ) {
			return;
		}
		global $post;
		if ( ! is_a( $post, 'WP_Post' ) ) {
			return;
		}
		$content    = (string) $post->post_content;
		$needs_css  = has_shortcode( $content, 'bw_dev_youtube' );
		// Only consider the legacy alias if we actually own it (i.e. the
		// old plugin isn't active and we registered it).
		if ( ! $needs_css && ! function_exists( 'bw_youtube_shortcode_handler' ) && has_shortcode( $content, 'bw_youtube' ) ) {
			$needs_css = true;
		}
		if ( ! $needs_css ) {
			return;
		}
		$handle = generate_block_asset_handle( 'bw-dev/youtube', 'style' );
		if ( wp_style_is( $handle, 'registered' ) ) {
			wp_enqueue_style( $handle );
		}
	}

	public function render_tab(): void {
		$current = (string) bw_dev()->settings()->get( $this->slug(), 'acf_field', self::DEFAULT_FIELD );
		$field_id = 'bw-dev-youtube-acf-field';
		$field_nm = BW_Dev_Settings::OPTION . '[' . $this->slug() . '][acf_field]';
		?>
		<p class="description">
			<?php
			printf(
				/* translators: %s: block name in bold */
				esc_html__( 'The %s block reads a YouTube URL from an ACF field on the current post and renders a responsive 16:9 iframe. Useful inside Kadence Query Loops where each post in a grid has its own video.', 'bw-dev' ),
				'<strong>BW YouTube Embed</strong>'
			);
			?>
		</p>

		<table class="form-table" role="presentation">
			<tbody>
				<tr>
					<th scope="row">
						<label for="<?php echo esc_attr( $field_id ); ?>"><?php esc_html_e( 'Default ACF field name', 'bw-dev' ); ?></label>
					</th>
					<td>
						<input type="text" id="<?php echo esc_attr( $field_id ); ?>" name="<?php echo esc_attr( $field_nm ); ?>" value="<?php echo esc_attr( $current ); ?>" class="regular-text" placeholder="<?php echo esc_attr( self::DEFAULT_FIELD ); ?>" />
						<p class="description">
							<?php
							printf(
								/* translators: %s: default field name */
								esc_html__( 'ACF field used when a block instance does not override it. Default: %s.', 'bw-dev' ),
								'<code>' . esc_html( self::DEFAULT_FIELD ) . '</code>'
							);
							?>
						</p>
						<p class="description">
							<?php esc_html_e( 'Each block insertion can override this from its sidebar (Block → Settings → YouTube source).', 'bw-dev' ); ?>
						</p>
					</td>
				</tr>
			</tbody>
		</table>

		<h3><?php esc_html_e( 'Supported URL formats', 'bw-dev' ); ?></h3>
		<ul style="list-style:disc; margin-left:20px;">
			<li><code>https://www.youtube.com/watch?v=XXXXX</code></li>
			<li><code>https://youtu.be/XXXXX</code></li>
			<li><code>https://www.youtube.com/embed/XXXXX</code></li>
			<li><code>https://www.youtube.com/shorts/XXXXX</code></li>
		</ul>

		<h3><?php esc_html_e( 'Shortcode', 'bw-dev' ); ?></h3>
		<p class="description">
			<?php
			printf(
				/* translators: 1: new shortcode, 2: legacy shortcode */
				esc_html__( 'Use %1$s in classic content. The legacy alias %2$s is registered automatically when the standalone bw-youtube-embed plugin is not active — so existing content keeps working after migration.', 'bw-dev' ),
				'<code>[bw_dev_youtube]</code>',
				'<code>[bw_youtube]</code>'
			);
			?>
		</p>
		<?php
	}

	public function uninstall(): void {
		// No-op. Root option drop handles persisted state.
	}
}
