<?php
/**
 * File Path: helpers/class-mbs-cover-renderer.php
 *
 * Buy Link Renderer
 *
 * Central class for rendering Order Now buttons and retailer links.
 * Handles both catalog modal path (JSON data attribute) and single-page accordion path.
 *
 * Depends on: MBS_Buy_Link_DAO (for link retrieval),
 *             MBS_Affiliate_Rewriter (PRO only),
 *             mbs_is_registered(), mbs_is_pro(), mbs_get_setting()
 *
 */

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

// Safety guard — prevents fatal error if the file is loaded twice
// (autoloader + any other require).
if ( class_exists( 'MBS_Buy_Link_Renderer' ) ) {
	return;
}

class MBS_Buy_Link_Renderer { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound -- mbs_/MBS_ prefix is correct; scanner not configured with plugin prefix

	/**
	 * Render the complete Order Now button + retailer group.
	 *
	 * In catalog context: renders a button with sanitized buy-links JSON for the modal.
	 * In single-page context: renders button + expandable retailer accordion.
	 */
	public static function render_order_now( int $post_id, ?object $format_row = null, array $atts = array() ): string {
		if ( ! mbs_is_registered() ) {
			return '';
		}

		$context = $atts['context'] ?? 'single';
		$class   = $atts['class'] ?? 'mbs-order-now';

		// Get links: prefer per-format overrides when format_row provided and PRO.
		// Global buy-link fallback: when a format has no per-format links, use the
		// book-level Global Buy Links rows (format_row_id IS NULL) so the buy-links
		// zone is never empty while the author has global links configured.
		if ( mbs_is_pro() && $format_row && ! empty( $format_row->id ) ) {
			$links = MBS_Buy_Link_DAO::get_for_format( (int) $format_row->id );
			if ( empty( $links ) ) {
				$links = MBS_Buy_Link_DAO::get_for_book( $post_id );
			}
		} else {
			$links = MBS_Buy_Link_DAO::get_for_book( $post_id );
		}

		// Exclude reader-platform links — rendered by section-reader-platforms.php.
		$links = array_values( array_filter( $links, static function ( $l ) {
			return ( $l->link_type ?? 'buy' ) === 'buy';
		} ) );

		$site_icon_url = MBS_Link_Icon_Helper::get_site_icon_url( 32 );

		if ( empty( $links ) ) {
			// Fallback: if purchase_link_text setting is a valid URL, render one Buy Now button.
			// Only applies to the single-page path; catalog always hides on empty (GP-UI-1).
			if ( $context !== 'catalog' ) {
				$fallback_url_raw = trim( mbs_get_setting( 'formatting', 'purchase_link_text', '' ) );
				$fallback_url     = ( '' !== $fallback_url_raw && filter_var( $fallback_url_raw, FILTER_VALIDATE_URL ) )
					? esc_url_raw( $fallback_url_raw )
					: '';
				if ( '' !== $fallback_url ) {
					$retailers_url = MBS_ASSETS_URL . 'images/retailers/';
					ob_start();
					?>
					<div class="mbs-buy-links mbs-buy-links-fallback" id="mbs-buy-links"
					     data-retailers-url="<?php echo esc_attr( $retailers_url ); ?>"
					     data-fallback-url="<?php echo esc_attr( $fallback_url ); ?>"
					     data-site-icon-url="<?php echo esc_attr( $site_icon_url ); ?>">
						<a href="<?php echo esc_url( $fallback_url ); ?>"
						   class="mbs-retailer-btn mbs-retailer-custom"
						   target="_blank" rel="noopener noreferrer">
							<span class="mbs-retailer-label"><?php esc_html_e( 'Buy Now', 'my-book-showroom' ); ?></span>
							</a>
					</div>
					<?php
					return ob_get_clean();
				}
			}
			return ''; // no links, no fallback URL → hide entirely (GP-UI-1 Golden Rule)
		}

		// Enqueue Gumroad overlay JS when any buy link targets Gumroad.
		// Uses event delegation — dynamically created .gumroad-button elements are handled.
		foreach ( $links as $_gumroad_link ) {
			if ( 'gumroad' === ( $_gumroad_link->retailer_key ?? '' ) ) {
				wp_enqueue_script( 'mbs-gumroad-overlay', 'https://gumroad.com/js/gumroad.js', array(), null, true ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion -- external CDN script
				break;
			}
		}

		ob_start();

		if ( $context === 'catalog' ) {
			// Catalog path: sanitize before JSON encoding for data attribute.
			$sanitized_links = array();
			foreach ( $links as $link ) {
				$sanitized_links[] = array(
					'url'          => esc_url_raw( $link->url ?? '' ),
					'label'        => sanitize_text_field( $link->link_label ?? '' ),
					'retailer_key' => sanitize_key( $link->retailer_key ?? '' ),
				);
			}
			$buy_links_json = wp_json_encode( array_values( $sanitized_links ) );

			?>
			<button type="button"
			        class="mbs-order-now-catalog button button-primary"
			        data-mbs-buy-links="<?php echo esc_attr( $buy_links_json ); ?>"
			        aria-label="<?php /* translators: %s: book title */ echo esc_attr( sprintf( __( 'Purchase options for %s', 'my-book-showroom' ), get_the_title( $post_id ) ) ); ?>">
				<?php echo esc_html( apply_filters( 'mbs_order_now_label', mbs_get_setting( 'formatting', 'purchase_link_text', __( 'Buy Now', 'my-book-showroom' ) ), $post_id ) );  // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- mbs_/MBS_ prefix is correct; scanner not configured with plugin prefix ?>
			</button>
			<?php
		} else {
			// Single-page path: direct retailer buttons, no accordion.
			// Buttons are always visible. JS (MBS.BuyLinks) rebuilds this
			// container when the user switches format tabs.
			$retailers_url    = MBS_ASSETS_URL . 'images/retailers/';
			$fallback_url_raw = trim( mbs_get_setting( 'formatting', 'purchase_link_text', '' ) );
			$fallback_url     = ( '' !== $fallback_url_raw && filter_var( $fallback_url_raw, FILTER_VALIDATE_URL ) )
				? esc_url_raw( $fallback_url_raw )
				: '';
			?>
			<div class="mbs-buy-links" id="mbs-buy-links"
			     data-retailers-url="<?php echo esc_attr( $retailers_url ); ?>"
			     data-fallback-url="<?php echo esc_attr( $fallback_url ); ?>"
			     data-site-icon-url="<?php echo esc_attr( $site_icon_url ); ?>">
				<?php foreach ( $links as $link ) :
					$retailer_key  = sanitize_key( $link->retailer_key ?? '' );
					$label         = ! empty( $link->link_label )
						? sanitize_text_field( $link->link_label )
						: MBS_Link_Icon_Helper::get_label( $retailer_key );
					// INSIGHTS-1: PRO installs route via /?mbs_click={id} for click tracking.
					$link_id_raw   = (int) ( $link->id ?? 0 );
					if ( mbs_is_pro() && $link_id_raw > 0 ) {
						$rewritten_url = home_url( '/?mbs_click=' . $link_id_raw );
					} else {
						$rewritten_url = mbs_is_pro()
							? MBS_Affiliate_Rewriter::rewrite( $link->url, $retailer_key )
							: $link->url;
					}
					$icon_att_id = isset( $link->icon_attachment_id ) ? (int) $link->icon_attachment_id : 0;
					if ( $icon_att_id > 0 ) {
						$img_src = wp_get_attachment_image_url( $icon_att_id, array( 24, 24 ) ) ?: ''; // R5-exempt: buy-link thumbnail admin display context
					} elseif ( $retailer_key ) {
						$img_src = MBS_Link_Icon_Helper::resolve_icon_src( $retailer_key, $retailers_url );
					} else {
						$img_src = $site_icon_url;
					}
				?>
					<a href="<?php echo esc_url( $rewritten_url ); ?>"
					   class="mbs-retailer-btn mbs-retailer-<?php echo esc_attr( $retailer_key ?: 'custom' ); ?><?php echo ( 'gumroad' === $retailer_key ) ? ' gumroad-button' : ''; ?>"
					   target="_blank" rel="noopener noreferrer"
					   aria-label="<?php echo esc_attr( $label . ' — Buy Now' ); ?>">
						<?php if ( $img_src ) : ?>
						<img src="<?php echo esc_url( $img_src ); ?>"
						     alt="" aria-hidden="true" class="mbs-retailer-logo"
						     width="24" height="24">
						<?php endif; ?>
						<span class="mbs-retailer-label"><?php echo esc_html( $label ); ?></span>
						</a>
				<?php endforeach; ?>
			</div>
			<?php
		}

		return ob_get_clean();
	}

	/**
	 * Get buy links for a book/format (used by shortcodes and templates).
	 *
	 * Depends on: MBS_Buy_Link_DAO
	 */
	public static function get_buy_links( int $post_id, ?int $format_row_id = null ): array {
		if ( mbs_is_pro() && $format_row_id ) {
			return MBS_Buy_Link_DAO::get_for_format( $format_row_id );
		}
		return MBS_Buy_Link_DAO::get_buy_links_for_book( $post_id );
	}

	/**
	 * Render a single retailer button (used in modal or quick view).
	 *
	 * Depends on: MBS_Affiliate_Rewriter (PRO only)
	 */
	/**
	 * Map a retailer_key to a human-readable display label.
	 *
	 * Used in server-side rendering and referenced by JS (MBS.BuyLinks.getLabel).
	 * Keys must match the PNG filenames in assets/images/retailers/.
	 *
	 * @param string $key  sanitize_key()-processed retailer key.
	 * @return string
	 */

	private static function get_retailer_label( string $key ): string {
		return MBS_Link_Icon_Helper::get_label( $key );
	}

	public static function render_single_button( object $link ): string {
		$rewritten_url = mbs_is_pro()
			? MBS_Affiliate_Rewriter::rewrite( $link->url, $link->retailer_key )
			: $link->url;

		$label = ! empty( $link->link_label )
			? sanitize_text_field( $link->link_label )
			: MBS_Link_Icon_Helper::get_label( sanitize_key( $link->retailer_key ?? '' ) );

		// ST-025 fix: sanitize_key() applied before use in URL path and CSS class.
		$safe_key    = sanitize_key( $link->retailer_key ?? '' );
		$icon_att_id = isset( $link->icon_attachment_id ) ? (int) $link->icon_attachment_id : 0;
		if ( $icon_att_id > 0 ) {
			$img_path = wp_get_attachment_image_url( $icon_att_id, array( 24, 24 ) ) ?: ''; // R5-exempt: buy-link thumbnail admin display context
		} elseif ( $safe_key ) {
			$img_path = MBS_Link_Icon_Helper::resolve_icon_src(
				$safe_key,
				MBS_ASSETS_URL . 'images/retailers/'
			);
		} else {
			$img_path = MBS_Link_Icon_Helper::get_site_icon_url( 32 );
		}

		ob_start();
		?>
		<a href="<?php echo esc_url( $rewritten_url ); ?>"
		   class="mbs-retailer-btn mbs-retailer-<?php echo esc_attr( $safe_key ?: 'custom' ); ?><?php echo ( 'gumroad' === $safe_key ) ? ' gumroad-button' : ''; ?>"
		   target="_blank" rel="noopener">
<?php if ( $img_path ) : ?>
			<img src="<?php echo esc_url( $img_path ); ?>"
			     alt="" aria-hidden="true" class="mbs-retailer-logo"
			     width="24" height="24">
		<?php endif; ?>
			<?php echo esc_html( $label ); ?>
		</a>
		<?php
		return ob_get_clean();
	}
}
