<?php
/**
 * Social Sharing Module.
 *
 * Adds social sharing buttons to single product pages and the wishlist page.
 * Supports automatic hook injection, block placement, or shortcode placement
 * for the product page, and hook-based injection for the wishlist page.
 *
 * @package JWP_STK
 */

namespace JWP_STK\Modules\SocialSharing;

use JWP_STK\Modules\Base_Module;

defined( 'ABSPATH' ) || exit;

/**
 * Module class.
 */
class Module extends Base_Module {

	/**
	 * Get the module slug.
	 *
	 * @return string
	 */
	public function get_slug() {
		return 'social-sharing';
	}

	/**
	 * Get default settings.
	 *
	 * @return array
	 */
	public function get_defaults() {
		return array(
			// Product page.
			'product_enabled'         => true,
			'product_injection'       => 'auto',
			'product_position'        => 'after_add_to_cart',
			'product_share_label'     => '',
			'product_share_text'      => 'Check out {title} — {url}',
			// Wishlist page.
			'wishlist_enabled'        => true,
			'wishlist_position'       => 'after_wishlist_table',
			'wishlist_share_label'    => '',
			'wishlist_share_text'     => "Here's my wishlist on {site_name} — {url}",
			// Shared / Customize tab.
			'buttons'                 => array( 'facebook', 'x', 'whatsapp', 'copy' ),
			'appearance'              => 'icon_text',
			'button_type'             => 'filled',
			'button_size'             => 'normal',
			'button_style_mode'       => 'custom',
			'button_text_color'       => '#ffffff',
			'button_bg_color'         => '#555d6c',
			'button_hover_bg_color'   => '#444d5c',
			'button_hover_text_color' => '#ffffff',
			'button_padding'          => '',
			'button_border_radius'    => '',
		);
	}

	/**
	 * Sanitize a setting value.
	 *
	 * @param string $key   Setting key.
	 * @param mixed  $value Setting value.
	 * @return mixed
	 */
	public function sanitize_setting( $key, $value ) {
		$allowed_injections = array( 'auto', 'block', 'shortcode' );
		$allowed_products   = array(
			'before_product_meta',
			'after_product_meta',
			'before_add_to_cart',
			'after_add_to_cart',
			'sticky_left',
			'sticky_right',
		);
		$allowed_wishlist   = array(
			'before_wishlist_table',
			'after_wishlist_table',
			'sticky_left',
			'sticky_right',
		);
		$allowed_buttons    = array( 'facebook', 'x', 'twitter', 'whatsapp', 'pinterest', 'email', 'sms', 'copy' );
		$allowed_appearance = array( 'icon_text', 'icon', 'text' );

		if ( 'product_injection' === $key ) {
			return in_array( $value, $allowed_injections, true ) ? $value : 'auto';
		}

		if ( 'product_position' === $key ) {
			return in_array( $value, $allowed_products, true ) ? $value : 'after_add_to_cart';
		}

		if ( 'wishlist_position' === $key ) {
			return in_array( $value, $allowed_wishlist, true ) ? $value : 'after_wishlist_table';
		}

		if ( 'buttons' === $key ) {
			if ( ! is_array( $value ) ) {
				return array( 'facebook', 'x', 'whatsapp', 'copy' );
			}
			return array_values( array_intersect( $value, $allowed_buttons ) );
		}

		if ( 'appearance' === $key ) {
			return in_array( $value, $allowed_appearance, true ) ? $value : 'icon_text';
		}

		if ( 'button_type' === $key ) {
			return in_array( $value, array( 'filled', 'outline' ), true ) ? $value : 'filled';
		}

		if ( 'button_size' === $key ) {
			return in_array( $value, array( 'small', 'normal', 'large' ), true ) ? $value : 'normal';
		}

		if ( 'button_style_mode' === $key ) {
			return in_array( $value, array( 'theme', 'custom' ), true ) ? $value : 'custom';
		}

		if ( in_array( $key, array( 'button_text_color', 'button_bg_color', 'button_hover_bg_color', 'button_hover_text_color' ), true ) ) {
			$sanitized = sanitize_hex_color( (string) $value );
			return $sanitized ? $sanitized : '';
		}

		if ( in_array( $key, array( 'button_padding', 'button_border_radius' ), true ) ) {
			if ( '' === (string) $value ) {
				return '';
			}
			$n = (int) $value;
			return $n >= 0 ? (string) $n : '';
		}

		if ( 'product_share_label' === $key || 'wishlist_share_label' === $key ) {
			return sanitize_text_field( (string) $value );
		}

		if ( 'product_share_text' === $key || 'wishlist_share_text' === $key ) {
			return sanitize_textarea_field( (string) $value );
		}

		return parent::sanitize_setting( $key, $value );
	}

	/**
	 * Initialise the module.
	 *
	 * @return void
	 */
	public function init() {
		// Always register shortcode so manual/block placement works.
		add_shortcode( 'storetoolkit_social_sharing', array( $this, 'render_shortcode' ) );

		if ( is_admin() ) {
			return;
		}

		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ) );

		// Product page.
		if ( $this->get_setting( 'product_enabled' ) && 'auto' === $this->get_setting( 'product_injection' ) ) {
			$this->register_product_hooks();
		}

		// Wishlist page.
		if ( $this->get_setting( 'wishlist_enabled' ) ) {
			$this->register_wishlist_hooks();
		}
	}

	// ──────────────────────────────────────────────────────────────────
	// Hook registration
	// ──────────────────────────────────────────────────────────────────

	/**
	 * Map each product position slug to a WooCommerce hook and priority.
	 *
	 * @return array<string, array{hook: string, priority: int}>
	 */
	private function get_product_hook_map() {
		return array(
			'before_product_meta' => array(
				'hook'     => 'woocommerce_single_product_summary',
				'priority' => 34,
			),
			'after_product_meta'  => array(
				'hook'     => 'woocommerce_single_product_summary',
				'priority' => 36,
			),
			'before_add_to_cart'  => array(
				'hook'     => 'woocommerce_single_product_summary',
				'priority' => 29,
			),
			'after_add_to_cart'   => array(
				'hook'     => 'woocommerce_single_product_summary',
				'priority' => 31,
			),
			'sticky_left'         => array(
				'hook'     => 'wp_footer',
				'priority' => 20,
			),
			'sticky_right'        => array(
				'hook'     => 'wp_footer',
				'priority' => 20,
			),
		);
	}

	/**
	 * Register the product page injection hook.
	 *
	 * @return void
	 */
	private function register_product_hooks() {
		$position = $this->get_setting( 'product_position' );
		$map      = $this->get_product_hook_map();

		if ( ! isset( $map[ $position ] ) ) {
			return;
		}

		$hook     = $map[ $position ]['hook'];
		$priority = $map[ $position ]['priority'];

		add_action( $hook, array( $this, 'render_product_buttons' ), $priority );
	}

	/**
	 * Register the wishlist page injection hooks.
	 *
	 * Hooks are fired by the Wishlist module inside render_wishlist_table().
	 * Sticky positions are rendered in wp_footer on wishlist pages.
	 *
	 * @return void
	 */
	private function register_wishlist_hooks() {
		$position = $this->get_setting( 'wishlist_position' );

		if ( 'sticky_left' === $position || 'sticky_right' === $position ) {
			add_action( 'wp_footer', array( $this, 'render_wishlist_sticky' ), 20 );
		} else {
			add_action( 'jwp_stk_before_wishlist_table', array( $this, 'render_wishlist_before_table' ) );
			add_action( 'jwp_stk_after_wishlist_table', array( $this, 'render_wishlist_after_table' ) );
		}
	}

	// ──────────────────────────────────────────────────────────────────
	// Render: product page
	// ──────────────────────────────────────────────────────────────────

	/**
	 * Render social sharing buttons on the single product page (auto injection).
	 *
	 * @return void
	 */
	public function render_product_buttons() {
		if ( ! is_product() ) {
			return;
		}

		$position = $this->get_setting( 'product_position' );
		$buttons  = (array) $this->get_setting( 'buttons' );

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

		// Sticky positions render via wp_footer.
		if ( 'sticky_left' === $position || 'sticky_right' === $position ) {
			$this->render_sticky( $buttons, $position );
			return;
		}

		global $product;
		if ( ! $product instanceof \WC_Product ) {
			return;
		}

		$url        = get_permalink( $product->get_id() );
		$title      = $product->get_name();
		$share_text = $this->resolve_share_text( 'product', $url, $title );

		$this->render_buttons( $buttons, $url, $share_text, 'product', $position );
	}

	// ──────────────────────────────────────────────────────────────────
	// Render: wishlist page
	// ──────────────────────────────────────────────────────────────────

	/**
	 * Render sharing buttons before the wishlist table.
	 *
	 * Fires on jwp_stk_before_wishlist_table.
	 *
	 * @return void
	 */
	public function render_wishlist_before_table() {
		if ( 'before_wishlist_table' !== $this->get_setting( 'wishlist_position' ) ) {
			return;
		}

		$this->output_wishlist_buttons();
	}

	/**
	 * Render sharing buttons after the wishlist table.
	 *
	 * Fires on jwp_stk_after_wishlist_table.
	 *
	 * @return void
	 */
	public function render_wishlist_after_table() {
		if ( 'after_wishlist_table' !== $this->get_setting( 'wishlist_position' ) ) {
			return;
		}

		$this->output_wishlist_buttons();
	}

	/**
	 * Render the wishlist sticky popup via wp_footer.
	 *
	 * @return void
	 */
	public function render_wishlist_sticky() {
		// Only render on wishlist page.
		$wishlist_page_id = $this->get_wishlist_page_id();
		if ( ! $wishlist_page_id || ! is_page( $wishlist_page_id ) ) {
			return;
		}

		$buttons = (array) $this->get_setting( 'buttons' );
		if ( empty( $buttons ) ) {
			return;
		}

		$url   = get_permalink( $wishlist_page_id );
		$title = get_the_title( $wishlist_page_id );

		$this->render_sticky( $buttons, $this->get_setting( 'wishlist_position' ), 'wishlist' );
	}

	/**
	 * Resolve the wishlist page ID from the active Wishlist module settings.
	 *
	 * @return int
	 */
	private function get_wishlist_page_id() {
		$plugin = \JWP_STK\Plugin::get_instance();
		if ( isset( $plugin->modules['wishlist'] ) ) {
			return (int) $plugin->modules['wishlist']->get_setting( 'wishlist_page_id' );
		}
		return 0;
	}

	/**
	 * Build the wishlist share URL.
	 *
	 * @return string
	 */
	private function get_wishlist_share_url() {
		$plugin = \JWP_STK\Plugin::get_instance();
		if ( isset( $plugin->modules['wishlist'] ) ) {
			return $plugin->modules['wishlist']->get_share_url();
		}

		// Fallback: current page URL.
		return get_permalink( get_queried_object_id() );
	}

	/**
	 * Output the wishlist sharing buttons (inline positions).
	 *
	 * @return void
	 */
	private function output_wishlist_buttons() {
		$buttons = (array) $this->get_setting( 'buttons' );
		if ( empty( $buttons ) ) {
			return;
		}

		$url     = $this->get_wishlist_share_url();
		$page_id = $this->get_wishlist_page_id();
		$title   = $page_id ? get_the_title( $page_id ) : get_bloginfo( 'name' );

		if ( ! $url ) {
			$url = $page_id ? get_permalink( $page_id ) : get_home_url();
		}

		$share_text = $this->resolve_share_text( 'wishlist', $url, $title );

		$this->render_buttons( $buttons, $url, $share_text, 'wishlist', $this->get_setting( 'wishlist_position' ) );
	}

	// ──────────────────────────────────────────────────────────────────
	// Shortcode
	// ──────────────────────────────────────────────────────────────────

	/**
	 * Render the [storetoolkit_social_sharing] shortcode.
	 *
	 * Accepts attributes:
	 *   - context: 'product' (default) | 'wishlist'
	 *
	 * @param array $atts Shortcode attributes.
	 * @return string HTML output.
	 */
	public function render_shortcode( $atts ) {
		$atts = shortcode_atts(
			array(
				'context' => 'product',
			),
			$atts,
			'storetoolkit_social_sharing'
		);

		$context = in_array( $atts['context'], array( 'product', 'wishlist' ), true )
			? $atts['context']
			: 'product';

		if ( ! wp_style_is( 'jwp-stk-social-sharing', 'enqueued' ) ) {
			$this->enqueue_assets();
		}

		ob_start();

		if ( 'wishlist' === $context ) {
			$this->output_wishlist_buttons();
		} else {
			global $product;
			if ( $product instanceof \WC_Product ) {
				$url        = get_permalink( $product->get_id() );
				$title      = $product->get_name();
				$buttons    = (array) $this->get_setting( 'buttons' );
				$share_text = $this->resolve_share_text( 'product', $url, $title );
				$this->render_buttons( $buttons, $url, $share_text, 'product', 'inline' );
			}
		}

		return ob_get_clean();
	}

	// ──────────────────────────────────────────────────────────────────
	// Rendering
	// ──────────────────────────────────────────────────────────────────

	/**
	 * Render inline social sharing buttons.
	 *
	 * @param string[] $buttons    Button slugs.
	 * @param string   $url        URL to share (raw, not encoded yet).
	 * @param string   $share_text Resolved share text (raw, not encoded yet).
	 * @param string   $context    'product' | 'wishlist' — added as a class modifier.
	 * @param string   $position   Position slug (used as additional class modifier).
	 * @return void
	 */
	private function render_buttons( array $buttons, $url, $share_text, $context, $position ) {
		if ( empty( $buttons ) ) {
			return;
		}

		$enc_url     = rawurlencode( esc_url_raw( $url ) );
		$enc_text    = rawurlencode( wp_strip_all_tags( $share_text ) );
		$modifier    = 'sticky_left' === $position || 'sticky_right' === $position ? 'sticky' : 'inline';
		$appearance  = $this->get_setting( 'appearance' ) ? $this->get_setting( 'appearance' ) : 'icon_text';
		$style_info  = $this->get_custom_style_attrs();
		$share_label = trim( (string) $this->get_setting( $context . '_share_label' ) );
		if ( '' === $share_label ) {
			$share_label = __( 'Share:', 'jetix-store-toolkit' );
		}
		?>
		<div class="jwp-stk-ss-wrap jwp-stk-ss--<?php echo esc_attr( $context ); ?> jwp-stk-ss--<?php echo esc_attr( $modifier ); ?> jwp-stk-ss--<?php echo esc_attr( $appearance ); ?><?php echo esc_attr( $style_info['classes'] ); ?>"<?php echo $style_info['style_attr']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- pre-escaped attr string built in get_custom_style_attrs(). ?>>
			<span class="jwp-stk-ss__label"><?php echo esc_html( $share_label ); ?></span>
			<ul class="jwp-stk-ss__list" role="list">
				<?php foreach ( $buttons as $button ) : ?>
					<?php $this->render_network_button( $button, $enc_url, $enc_text ); ?>
				<?php endforeach; ?>
			</ul>
		</div>
		<?php
	}

	/**
	 * Render the sticky popup for a given side.
	 *
	 * @param string[] $buttons  Network button slugs.
	 * @param string   $position 'sticky_left' | 'sticky_right'.
	 * @param string   $context  'product' | 'wishlist'.
	 * @return void
	 */
	private function render_sticky( array $buttons, $position, $context = 'product' ) {
		if ( empty( $buttons ) ) {
			return;
		}

		// Resolve URL and title.
		if ( 'wishlist' === $context ) {
			$page_id = $this->get_wishlist_page_id();
			$url     = $this->get_wishlist_share_url();
			if ( ! $url ) {
				$url = $page_id ? get_permalink( $page_id ) : get_home_url();
			}
			$title = $page_id ? get_the_title( $page_id ) : get_bloginfo( 'name' );
		} else {
			global $product;
			if ( ! $product instanceof \WC_Product ) {
				return;
			}
			$url   = get_permalink( $product->get_id() );
			$title = $product->get_name();
		}

		$share_text = $this->resolve_share_text( $context, $url, $title );
		$enc_url    = rawurlencode( esc_url_raw( $url ) );
		$enc_text   = rawurlencode( wp_strip_all_tags( $share_text ) );
		$side       = 'sticky_right' === $position ? 'right' : 'left';
		$appearance = $this->get_setting( 'appearance' ) ? $this->get_setting( 'appearance' ) : 'icon_text';
		$style_info = $this->get_custom_style_attrs();
		?>
		<div class="jwp-stk-ss-sticky jwp-stk-ss-sticky--<?php echo esc_attr( $side ); ?> jwp-stk-ss--<?php echo esc_attr( $context ); ?> jwp-stk-ss--<?php echo esc_attr( $appearance ); ?><?php echo esc_attr( $style_info['classes'] ); ?>"<?php echo $style_info['style_attr']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- pre-escaped attr string built in get_custom_style_attrs(). ?> role="complementary" aria-label="<?php esc_attr_e( 'Share this page', 'jetix-store-toolkit' ); ?>">
			<button class="jwp-stk-ss-sticky__toggle" aria-expanded="false" aria-controls="jwp-stk-ss-sticky-list-<?php echo esc_attr( $side . '-' . $context ); ?>" aria-label="<?php esc_attr_e( 'Toggle social sharing', 'jetix-store-toolkit' ); ?>">
				<?php echo wp_kses( $this->get_share_svg(), $this->get_allowed_svg_tags() ); ?>
			</button>
			<ul class="jwp-stk-ss__list jwp-stk-ss-sticky__list" id="jwp-stk-ss-sticky-list-<?php echo esc_attr( $side . '-' . $context ); ?>" role="list" hidden>
				<?php foreach ( $buttons as $button ) : ?>
					<?php $this->render_network_button( $button, $enc_url, $enc_text ); ?>
				<?php endforeach; ?>
			</ul>
		</div>
		<?php
	}

	/**
	 * Build CSS class modifier and inline style attribute for the custom button style.
	 *
	 * When button_style_mode is 'custom', returns a class modifier and a style
	 * attribute string containing CSS custom properties for any non-empty color
	 * or dimension settings.
	 *
	 * @return array{ classes: string, style_attr: string }
	 */
	private function get_custom_style_attrs() {
		$mode        = $this->get_setting( 'button_style_mode' ) ? $this->get_setting( 'button_style_mode' ) : 'custom';
		$button_type = $this->get_setting( 'button_type' ) ? $this->get_setting( 'button_type' ) : 'filled';
		$button_size = $this->get_setting( 'button_size' ) ? $this->get_setting( 'button_size' ) : 'normal';
		$type_class  = ' jwp-stk-ss--' . $button_type;
		$size_class  = 'normal' !== $button_size ? ' jwp-stk-ss--' . $button_size : '';

		if ( 'theme' === $mode ) {
			return array(
				'classes'    => ' jwp-stk-ss--theme' . $type_class . $size_class,
				'style_attr' => '',
			);
		}

		$css_vars   = array();
		$text_color = $this->get_setting( 'button_text_color' );
		$bg_color   = $this->get_setting( 'button_bg_color' );
		$hover_bg   = $this->get_setting( 'button_hover_bg_color' );
		$hover_text = $this->get_setting( 'button_hover_text_color' );
		$padding    = $this->get_setting( 'button_padding' );
		$radius     = $this->get_setting( 'button_border_radius' );

		if ( $text_color ) {
			$css_vars[] = '--jwp-ss-text: ' . esc_attr( $text_color );
		}
		if ( $bg_color ) {
			$css_vars[] = '--jwp-ss-bg: ' . esc_attr( $bg_color );
		}
		if ( $hover_bg ) {
			$css_vars[] = '--jwp-ss-hover-bg: ' . esc_attr( $hover_bg );
		}
		if ( $hover_text ) {
			$css_vars[] = '--jwp-ss-hover-text: ' . esc_attr( $hover_text );
		}
		if ( '' !== (string) $padding && is_numeric( $padding ) ) {
			$css_vars[] = '--jwp-ss-padding: ' . (int) $padding . 'px';
		}
		if ( '' !== (string) $radius && is_numeric( $radius ) ) {
			$css_vars[] = '--jwp-ss-radius: ' . (int) $radius . 'px';
		}

		$style_attr = ! empty( $css_vars )
			? ' style="' . implode( '; ', $css_vars ) . '"'
			: '';

		return array(
			'classes'    => ' jwp-stk-ss--custom' . $type_class . $size_class,
			'style_attr' => $style_attr,
		);
	}

	/**
	 * Render a single network button list item.
	 *
	 * @param string $network Validated network slug.
	 * @param string $url     URL-encoded share URL.
	 * @param string $title   URL-encoded share title.
	 * @return void
	 */
	private function render_network_button( $network, $url, $title ) {
		$allowed = array( 'facebook', 'x', 'twitter', 'pinterest', 'whatsapp', 'email', 'sms', 'copy' );
		if ( ! in_array( $network, $allowed, true ) ) {
			return;
		}

		$labels = array(
			'facebook'  => __( 'Share on Facebook', 'jetix-store-toolkit' ),
			'x'         => __( 'Share on X', 'jetix-store-toolkit' ),
			'twitter'   => __( 'Share on Twitter', 'jetix-store-toolkit' ),
			'pinterest' => __( 'Share on Pinterest', 'jetix-store-toolkit' ),
			'whatsapp'  => __( 'Share on WhatsApp', 'jetix-store-toolkit' ),
			'email'     => __( 'Share via Email', 'jetix-store-toolkit' ),
			'sms'       => __( 'Share via Text Message', 'jetix-store-toolkit' ),
			'copy'      => __( 'Copy link', 'jetix-store-toolkit' ),
		);

		$href  = $this->get_share_href( $network, $url, $title );
		$svg   = $this->get_network_svg( $network );
		$kses  = $this->get_allowed_svg_tags();
		$label = $labels[ $network ];

		if ( 'copy' === $network ) {
			printf(
				'<li class="jwp-stk-ss__item jwp-stk-ss__item--%1$s"><button type="button" class="jwp-stk-ss__btn jwp-stk-ss__copy-btn" data-url="%2$s" aria-label="%3$s">%4$s<span class="jwp-stk-ss__net-name">%5$s</span></button></li>',
				esc_attr( $network ),
				esc_attr( rawurldecode( $url ) ),
				esc_attr( $label ),
				wp_kses( $svg, $kses ),
				esc_html( __( 'Copy', 'jetix-store-toolkit' ) )
			);
			return;
		}

		printf(
			'<li class="jwp-stk-ss__item jwp-stk-ss__item--%1$s"><a class="jwp-stk-ss__btn" href="%2$s" target="_blank" rel="noopener noreferrer" aria-label="%3$s">%4$s<span class="jwp-stk-ss__net-name">%5$s</span></a></li>',
			esc_attr( $network ),
			esc_url( $href ),
			esc_attr( $label ),
			wp_kses( $svg, $kses ),
			esc_html( $this->get_network_label( $network ) )
		);
	}

	/**
	 * Get the short display label for a network.
	 *
	 * @param string $network Network slug.
	 * @return string
	 */
	private function get_network_label( $network ) {
		$labels = array(
			'facebook'  => 'Facebook',
			'x'         => 'X',
			'twitter'   => 'Twitter',
			'pinterest' => 'Pinterest',
			'whatsapp'  => 'WhatsApp',
			'email'     => __( 'Email', 'jetix-store-toolkit' ),
			'sms'       => __( 'Text', 'jetix-store-toolkit' ),
			'copy'      => __( 'Copy', 'jetix-store-toolkit' ),
		);
		return isset( $labels[ $network ] ) ? $labels[ $network ] : $network;
	}

	/**
	 * Build the share href for a given network.
	 *
	 * @param string $network URL-encoded URL.
	 * @param string $url     URL-encoded share URL.
	 * @param string $title   URL-encoded share title.
	 * @return string
	 */
	private function get_share_href( $network, $url, $title ) {
		$hrefs = array(
			'facebook'  => 'https://www.facebook.com/sharer/sharer.php?u=' . $url,
			'x'         => 'https://x.com/intent/post?url=' . $url . '&text=' . $title,
			'twitter'   => 'https://twitter.com/intent/tweet?url=' . $url . '&text=' . $title,
			'pinterest' => 'https://pinterest.com/pin/create/button/?url=' . $url . '&description=' . $title,
			'whatsapp'  => 'https://wa.me/?text=' . $title . '%20' . $url,
			'email'     => 'mailto:?subject=' . $title . '&body=' . $url,
			'sms'       => 'sms:?body=' . $title . '%20' . $url,
			'copy'      => '#',
		);
		return isset( $hrefs[ $network ] ) ? $hrefs[ $network ] : '#';
	}

	// ──────────────────────────────────────────────────────────────────
	// Share text
	// ──────────────────────────────────────────────────────────────────

	/**
	 * Resolve the share text for a given context, replacing placeholders.
	 *
	 * Placeholders: {title}, {url}, {site_name}.
	 * Falls back to "{title}" when no custom text is set.
	 *
	 * @param string $context 'product' | 'wishlist'.
	 * @param string $url     Raw share URL.
	 * @param string $title   Page / product title.
	 * @return string Resolved share text (raw, not URL-encoded).
	 */
	private function resolve_share_text( $context, $url, $title ) {
		$key = 'product' === $context ? 'product_share_text' : 'wishlist_share_text';
		$raw = trim( (string) $this->get_setting( $key ) );

		if ( '' === $raw ) {
			$raw = 'product' === $context
				? 'Check out {title} — {url}'
				: "Here's my wishlist on {site_name} — {url}";
		}

		return str_replace(
			array( '{title}', '{url}', '{site_name}' ),
			array( $title, $url, get_bloginfo( 'name' ) ),
			$raw
		);
	}

	// ──────────────────────────────────────────────────────────────────
	// Assets
	// ──────────────────────────────────────────────────────────────────

	/**
	 * Enqueue frontend styles and inline copy-to-clipboard script.
	 *
	 * @return void
	 */
	public function enqueue_assets() {
		wp_enqueue_style(
			'jwp-stk-social-sharing',
			JWP_STK_PLUGIN_URL . 'assets/css/social-sharing.css',
			array(),
			JWP_STK_VERSION
		);

		// Inline JS for copy-to-clipboard and sticky toggle — no separate file needed.
		// Explicitly enqueue wp-dom-ready so the inline script is guaranteed to output.
		wp_enqueue_script( 'wp-dom-ready' );
		wp_add_inline_script( 'wp-dom-ready', $this->get_inline_js() );
	}

	/**
	 * Return the inline JS string.
	 *
	 * @return string
	 */
	private function get_inline_js() {
		return <<<'JS'
( function () {
	if ( typeof document === 'undefined' ) return;

	function jwpStkSSInit() {

		// ── Copy to clipboard ─────────────────────────────────────────
		document.querySelectorAll( '.jwp-stk-ss__copy-btn' ).forEach( function ( btn ) {
			btn.addEventListener( 'click', function () {
				var url = btn.getAttribute( 'data-url' );
				if ( ! url ) return;
				if ( navigator.clipboard && navigator.clipboard.writeText ) {
					navigator.clipboard.writeText( url )
						.then( function () { jwpStkSSFlashCopied( btn ); } )
						.catch( function () { jwpStkSSFallbackCopy( url, btn ); } );
				} else {
					jwpStkSSFallbackCopy( url, btn );
				}
			} );
		} );

		function jwpStkSSFallbackCopy( url, btn ) {
			var ta = document.createElement( 'textarea' );
			ta.value = url;
			ta.setAttribute( 'readonly', '' );
			ta.style.position = 'fixed';
			ta.style.left     = '-9999px';
			ta.style.top      = '-9999px';
			document.body.appendChild( ta );
			ta.select();
			try { document.execCommand( 'copy' ); } catch ( e ) {}
			document.body.removeChild( ta );
			jwpStkSSFlashCopied( btn );
		}

		function jwpStkSSFlashCopied( btn ) {
			var label = btn.querySelector( '.jwp-stk-ss__net-name' );
			if ( ! label ) return;
			var original = label.textContent;
			label.textContent = btn.getAttribute( 'data-copied-label' ) || 'Copied!';
			setTimeout( function () { label.textContent = original; }, 2000 );
		}

		// ── Sticky toggle ─────────────────────────────────────────────
		document.querySelectorAll( '.jwp-stk-ss-sticky__toggle' ).forEach( function ( toggle ) {
			toggle.addEventListener( 'click', function () {
				var sticky   = toggle.closest( '.jwp-stk-ss-sticky' );
				if ( ! sticky ) return;
				var list     = sticky.querySelector( '.jwp-stk-ss-sticky__list' );
				var expanded = toggle.getAttribute( 'aria-expanded' ) === 'true';
				toggle.setAttribute( 'aria-expanded', expanded ? 'false' : 'true' );
				if ( list ) {
					if ( expanded ) {
						list.setAttribute( 'hidden', '' );
					} else {
						list.removeAttribute( 'hidden' );
					}
				}
				sticky.classList.toggle( 'is-open', ! expanded );
			} );
		} );
	}

	// Run immediately if DOM is ready; otherwise wait for it.
	if ( document.readyState === 'loading' ) {
		document.addEventListener( 'DOMContentLoaded', jwpStkSSInit );
	} else {
		jwpStkSSInit();
	}
} )();
JS;
	}

	// ──────────────────────────────────────────────────────────────────
	// SVG helpers
	// ──────────────────────────────────────────────────────────────────

	/**
	 * Return the SVG icon markup for a network.
	 *
	 * @param string $network Network slug.
	 * @return string Safe SVG markup.
	 */
	private function get_network_svg( $network ) {
		$svgs = array(
			'facebook'  => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M22 12a10 10 0 1 0-11.563 9.876V14.89h-2.54V12h2.54V9.797c0-2.506 1.492-3.89 3.777-3.89 1.094 0 2.238.195 2.238.195v2.46h-1.26c-1.243 0-1.63.771-1.63 1.562V12h2.773l-.443 2.89h-2.33v6.988A10.002 10.002 0 0 0 22 12z"/></svg>',
			'x'         => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>',
			'twitter'   => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M23.953 4.57a10 10 0 0 1-2.825.775 4.958 4.958 0 0 0 2.163-2.723 9.99 9.99 0 0 1-3.127 1.195 4.92 4.92 0 0 0-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 0 0-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 0 1-2.228-.616v.06a4.923 4.923 0 0 0 3.946 4.827 4.996 4.996 0 0 1-2.212.085 4.937 4.937 0 0 0 4.604 3.417 9.868 9.868 0 0 1-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 0 0 7.557 2.209c9.054 0 13.999-7.496 13.999-13.986 0-.209 0-.42-.015-.63a9.936 9.936 0 0 0 2.46-2.548l-.047-.02z"/></svg>',
			'pinterest' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M12 2C6.477 2 2 6.477 2 12c0 4.236 2.636 7.855 6.356 9.312-.088-.791-.167-2.005.035-2.868.181-.78 1.172-4.97 1.172-4.97s-.299-.598-.299-1.482c0-1.388.806-2.428 1.808-2.428.853 0 1.267.641 1.267 1.408 0 .858-.548 2.143-.83 3.33-.236.995.499 1.806 1.476 1.806 1.772 0 3.136-1.867 3.136-4.562 0-2.387-1.715-4.055-4.163-4.055-2.836 0-4.499 2.126-4.499 4.324 0 .857.33 1.775.742 2.277a.3.3 0 0 1 .069.284c-.076.315-.244.995-.277 1.134-.044.183-.146.222-.337.134-1.249-.581-2.03-2.407-2.03-3.874 0-3.154 2.292-6.052 6.608-6.052 3.469 0 6.165 2.473 6.165 5.776 0 3.447-2.173 6.22-5.19 6.22-1.013 0-1.967-.527-2.292-1.148l-.623 2.378c-.226.869-.835 1.958-1.244 2.621.937.29 1.931.446 2.962.446C17.523 22 22 17.523 22 12S17.523 2 12 2z"/></svg>',
			'whatsapp'  => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 0 1-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 0 1-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 0 1 2.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0 0 12.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 0 0 5.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 0 0-3.48-8.413Z"/></svg>',
			'email'     => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></svg>',
			'sms'       => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>',
			'copy'      => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>',
		);
		return isset( $svgs[ $network ] ) ? $svgs[ $network ] : '';
	}

	/**
	 * Return the generic share SVG (for sticky toggle button).
	 *
	 * @return string
	 */
	private function get_share_svg() {
		return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/></svg>';
	}

	/**
	 * Allowed HTML tags and attributes for SVG output.
	 *
	 * @return array
	 */
	private function get_allowed_svg_tags() {
		return array(
			'svg'    => array(
				'xmlns'           => array(),
				'viewbox'         => array(),
				'width'           => array(),
				'height'          => array(),
				'fill'            => array(),
				'stroke'          => array(),
				'stroke-width'    => array(),
				'stroke-linecap'  => array(),
				'stroke-linejoin' => array(),
				'aria-hidden'     => array(),
			),
			'path'   => array(
				'd'         => array(),
				'fill'      => array(),
				'fill-rule' => array(),
				'clip-rule' => array(),
			),
			'circle' => array(
				'cx'   => array(),
				'cy'   => array(),
				'r'    => array(),
				'fill' => array(),
			),
			'rect'   => array(
				'x'      => array(),
				'y'      => array(),
				'rx'     => array(),
				'ry'     => array(),
				'width'  => array(),
				'height' => array(),
			),
			'line'   => array(
				'x1' => array(),
				'y1' => array(),
				'x2' => array(),
				'y2' => array(),
			),
		);
	}
}
