<?php
/**
 * GT BOGO Engine — WhatsApp Commerce Superpower (Enterprise Edition)
 *
 * Full enterprise WhatsApp integration for WooCommerce:
 *
 * INTELLIGENCE
 *   - Orchestrator-gated: fully autonomous enable/suppress decision
 *   - Intent score-aware: copy and prominence scale with intent level
 *   - Archetype-aware: different message templates per visitor archetype
 *   - Journey-stage aware: new vs returning vs VIP vs at-risk messaging
 *   - Deal-aware: appends active deal offer to pre-filled message
 *   - Cart-summary injection: cart total + item count in message
 *   - Signal Bus write_signal(): logs engagement to behavioral_intent
 *
 * MULTI-NUMBER ROUTING
 *   - Primary + fallback phone number
 *   - Per-country number routing (comma-separated country:number pairs)
 *   - Per-agent routing by cart value tier (low/mid/high value)
 *   - VIP customers routed to dedicated VIP support line
 *
 * BUSINESS HOURS & AVAILABILITY
 *   - Configurable timezone-aware business hours (open/close time per day)
 *   - "Available now" vs "Leave a message — we reply within X hours" copy
 *   - Holiday mode: override label and message on configured dates
 *   - Offline indicator when outside business hours
 *
 * MESSAGE TEMPLATES
 *   - 6 conversation starters: Question, Support, Claim Offer, Track Order, Returns, VIP Service
 *   - Template selected automatically based on page context and intent score
 *   - Cart total, item count, and active deal appended automatically
 *   - Customer name injected for logged-in users
 *   - Multi-language: browser Accept-Language header used to select template
 *   - Store name and URL included in all messages
 *
 * DISPLAY & UX
 *   - 3 display modes: Floating Button (default), Sticky Bar, Inline
 *   - Intensity-driven: subtle = icon only, moderate = icon+label, bold = pulsing badge
 *   - Scroll-trigger: appear after configurable scroll depth (0–100%)
 *   - Time-trigger: appear after configurable delay (0–30s)
 *   - Entrance animation via CSS token system
 *   - Notification badge when pending deal exists
 *   - Drag handle for mobile repositioning (floating mode)
 *   - Desktop QR code fallback (renders QR link in tooltip/popover)
 *   - Dismissible with configurable re-show delay
 *   - WCAG 2.1 AA compliant: ARIA roles, keyboard navigation, touch targets ≥44px
 *   - prefers-reduced-motion respected
 *   - All CSS via CSS custom property tokens — zero hardcoded values
 *   - Luxury compliant: no GT BOGO branding visible to customers
 *   - No fake urgency: honest, helpful copy only
 *
 * FREQUENCY & FATIGUE CONTROL
 *   - Session-level: only show once per session by default
 *   - Cross-session: configurable cooldown hours after click (default: 24h)
 *   - Max impressions per user per day (default: 3)
 *   - Never show if customer messaged in last N hours
 *
 * ANALYTICS & TRACKING
 *   - Click tracking via AJAX to Outcome Capture (gtbogo_outcomes table)
 *   - Impression logging (show events)
 *   - Dismissal tracking
 *   - Conversion attribution: marks order as WhatsApp-assisted if clicked in session
 *   - A/B testable via Challenger integration
 *
 * RESTRICTIONS (hard rules)
 *   - Cart/checkout pages only — never product, shop, category, or home pages
 *   - Mobile devices only (configurable — can enable for desktop)
 *   - Country allow-list enforced via WC geolocation
 *   - Phone number required — gracefully disabled if not configured
 *
 * @package GT_BOGO_Engine
 * @since   3.23.3
 */
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class GT_BOGO_WhatsApp_Commerce {
 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound

	private $id           = 'whatsapp_commerce';
	private ?array $_cfg  = null;
	private ?array $_anim = null;

	// Option keys
	const OPT_PHONE           = 'gtbogo_sp_whatsapp_phone';
	const OPT_PHONE_VIP       = 'gtbogo_sp_whatsapp_phone_vip';
	const OPT_PHONE_FALLBACK  = 'gtbogo_sp_whatsapp_phone_fallback';
	const OPT_COUNTRY_ROUTING = 'gtbogo_sp_whatsapp_country_routing'; // JSON: {"US":"15551234","UK":"447911"}
	const OPT_VALUE_ROUTING   = 'gtbogo_sp_whatsapp_value_routing';   // JSON: {"high":{"min":200,"phone":"..."}}
	const OPT_LABEL           = 'gtbogo_sp_whatsapp_label';
	const OPT_LABEL_OFFLINE   = 'gtbogo_sp_whatsapp_label_offline';
	const OPT_COUNTRIES       = 'gtbogo_sp_whatsapp_countries';        // comma-separated ISO codes, empty = all
	const OPT_DESKTOP         = 'gtbogo_sp_whatsapp_desktop';          // 1 = show on desktop too
	const OPT_SCROLL_PCT      = 'gtbogo_sp_whatsapp_scroll_pct';       // 0-100
	const OPT_DELAY_SECS      = 'gtbogo_sp_whatsapp_delay_secs';       // 0-30
	const OPT_DISPLAY_MODE    = 'gtbogo_sp_whatsapp_display_mode';     // floating|sticky|inline
	const OPT_HOURS_ENABLED   = 'gtbogo_sp_whatsapp_hours_enabled';    // 1/0
	const OPT_HOURS_OPEN      = 'gtbogo_sp_whatsapp_hours_open';       // "09:00"
	const OPT_HOURS_CLOSE     = 'gtbogo_sp_whatsapp_hours_close';      // "18:00"
	const OPT_HOURS_DAYS      = 'gtbogo_sp_whatsapp_hours_days';       // "1,2,3,4,5" (Mon-Fri)
	const OPT_HOURS_TZ        = 'gtbogo_sp_whatsapp_hours_tz';         // timezone string
	const OPT_HOURS_REPLY     = 'gtbogo_sp_whatsapp_hours_reply';      // "2 hours"
	const OPT_COOLDOWN_HRS    = 'gtbogo_sp_whatsapp_cooldown_hrs';     // hours after click
	const OPT_MAX_IMPR        = 'gtbogo_sp_whatsapp_max_impressions';  // per day
	const OPT_HOLIDAY_DATES   = 'gtbogo_sp_whatsapp_holiday_dates';    // "2024-12-25,2024-01-01"
	const OPT_HOLIDAY_LABEL   = 'gtbogo_sp_whatsapp_holiday_label';
	const OPT_HOLIDAY_MSG     = 'gtbogo_sp_whatsapp_holiday_msg';

	// Frequency cap transient keys
	const TRANSIENT_CLICK = 'gtbogo_wa_click_';   // + user/session id
	const TRANSIENT_IMPR  = 'gtbogo_wa_impr_';    // + user/session id + date

	public function __construct() {
		if ( ! $this->enabled() ) {
			return;
		}
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue' ) );
		add_action( 'wp_footer', array( $this, 'render' ), 99 );
		add_action( 'wp_ajax_gtbogo_wa_click', array( __CLASS__, 'ajax_track_click' ) );
		add_action( 'wp_ajax_nopriv_gtbogo_wa_click', array( __CLASS__, 'ajax_track_click' ) );
		add_action( 'wp_ajax_gtbogo_wa_dismiss', array( __CLASS__, 'ajax_track_dismiss' ) );
		add_action( 'wp_ajax_nopriv_gtbogo_wa_dismiss', array( __CLASS__, 'ajax_track_dismiss' ) );
	}

	// ── Standard Superpower Template ─────────────────────────────────────────


	/**
	 * Get AI-generated copy for a field, with fallback to default.
	 * Reads from gtbogo_sp_{id}_ai_copy option set by GT_BOGO_AI_Copywriter.
	 *
	 * @param string $field   Copy field name (headline, message, cta, badge_text, etc.)
	 * @param string $default Default text if AI copy not available
	 * @return string
	 * @since 5.0.0
	 */
	private function ai_copy( string $field, string $default = '' ): string {
		$copy = get_option( 'gtbogo_sp_' . $this->id . '_ai_copy', array() );
		return ! empty( $copy[ $field ] ) ? wp_kses_post( $copy[ $field ] ) : $default;
	}


	private function enabled(): bool {
		// Orchestrator gate
		if ( class_exists( 'GT_BOGO_Superpower_Orchestrator' ) ) {
			$orch = GT_BOGO_Superpower_Orchestrator::decision( $this->id );
			if ( isset( $orch['enabled'] ) && ! $orch['enabled'] ) {
				return false;
			}
		}
		if ( ! (bool) get_option( 'gtbogo_sp_' . $this->id . '_enabled', 0 ) ) {
			return false;
		}
		if ( get_option( 'gtbogo_sp_' . $this->id . '_intensity', 'subtle' ) === 'off' ) {
			return false;
		}
		// Phone required
		if ( empty( get_option( self::OPT_PHONE, '' ) ) ) {
			return false;
		}
		// Pages: cart/checkout only
		if ( ! function_exists( 'is_cart' ) ) {
			return false;
		}
		if ( ! is_cart() && ! is_checkout() ) {
			return false;
		}
		// Device
		$desktop_ok = (bool) get_option( self::OPT_DESKTOP, 0 );
		if ( ! $desktop_ok && ! wp_is_mobile() ) {
			return false;
		}
		// Country
		$allowed = $this->get_allowed_countries();
		if ( ! empty( $allowed ) && ! $this->visitor_in_country( $allowed ) ) {
			return false;
		}
		// Frequency cap
		if ( $this->is_frequency_capped() ) {
			return false;
		}
		return true;
	}

	private function cfg(): array {
		if ( $this->_cfg === null && class_exists( 'GT_BOGO_Superpower_Theme_Intelligence' ) ) {
			$this->_cfg = GT_BOGO_Superpower_Theme_Intelligence::resolve( $this->id );
		}
		return $this->_cfg ?? array();
	}

	private function intensity(): string {
		if ( class_exists( 'GT_BOGO_Superpower_Orchestrator' ) ) {
			$d = GT_BOGO_Superpower_Orchestrator::decision( $this->id );
			if ( ! empty( $d['intensity'] ) ) {
				return $d['intensity'];
			}
		}
		return $this->cfg()['intensity'] ?? get_option( 'gtbogo_sp_' . $this->id . '_intensity', 'subtle' );
	}

	private function anim(): array {
		if ( $this->_anim === null && class_exists( 'GT_BOGO_Superpower_Theme_Intelligence' ) ) {
			$this->_anim = GT_BOGO_Superpower_Theme_Intelligence::animation_profile( $this->cfg() );
		}
		return $this->_anim ?? array(
			'use_gamification' => false,
			'use_entrance'     => false,
			'use_micro'        => true,
			'gamif_intensity'  => 'subtle',
			'speed_token'      => 'var(--gtbogo-sp-duration-subtle,350ms)',
			'ease_token'       => 'var(--gtbogo-sp-ease-subtle,ease)',
			'family'           => 'universal',
		);
	}

	// ── Signal Bus ───────────────────────────────────────────────────────────

	public static function write_signal( int $user_id = 0 ): void {
		if ( ! class_exists( 'GT_BOGO_Signal_Bus' ) ) {
			return;
		}
		$key     = self::TRANSIENT_CLICK . ( $user_id ?: ( session_id() ?: 'guest' ) );
		$clicked = (bool) get_transient( $key );
		// 5.0 = clicked WhatsApp this session (strong behavioral intent signal)
		GT_BOGO_Signal_Bus::set( 'behavioral_intent', $clicked ? 5.0 : 0.0 );
	}

	// ── Country / Routing ────────────────────────────────────────────────────

	private function get_allowed_countries(): array {
		$raw = get_option( self::OPT_COUNTRIES, '' );
		if ( empty( $raw ) ) {
			return array();
		}
		return array_filter( array_map( 'trim', explode( ',', strtoupper( $raw ) ) ) );
	}

	private function visitor_in_country( array $allowed ): bool {
		$country = $this->detect_country();
		return empty( $country ) || in_array( $country, $allowed, true );
	}

	private function detect_country(): string {
		if ( function_exists( 'WC' ) && WC()->customer ) {
			$c = WC()->customer->get_billing_country();
			if ( $c ) {
				return strtoupper( $c );
			}
		}
		if ( class_exists( 'WC_Geolocation' ) ) {
			$geo = WC_Geolocation::geolocate_ip();
			return strtoupper( $geo['country'] ?? '' );
		}
		return '';
	}

	private function get_routed_phone(): string {
		$customer_id = is_user_logged_in() ? get_current_user_id() : 0;
		$ltv         = $customer_id && class_exists( 'GT_BOGO_Signal_Bus' )
			? (float) GT_BOGO_Signal_Bus::get( 'ltv_score', 0 )
			: 0;

		// VIP routing: LTV score >= 4.0 or VIP tier set
		$is_vip = $ltv >= 4.0;
		if ( ! $is_vip && $customer_id ) {
			$profile = class_exists( 'GT_BOGO_Customer_Profile_Tracker' )
				? GT_BOGO_Customer_Profile_Tracker::get_profile( $customer_id )
				: array();
			$is_vip  = ! empty( $profile['vip_tier'] );
		}
		if ( $is_vip ) {
			$vip_phone = get_option( self::OPT_PHONE_VIP, '' );
			if ( $vip_phone ) {
				return preg_replace( '/[^0-9]/', '', $vip_phone );
			}
		}

		// Cart value routing
		$cart_total    = function_exists( 'WC' ) && WC()->cart
			? (float) WC()->cart->get_cart_contents_total()
			: 0;
		$value_routing = json_decode( get_option( self::OPT_VALUE_ROUTING, '{}' ), true ) ?: array();
		if ( ! empty( $value_routing ) ) {
			uasort( $value_routing, fn( $a, $b ) => $b['min'] <=> $a['min'] );
			foreach ( $value_routing as $tier ) {
				if ( isset( $tier['min'] ) && $cart_total >= (float) $tier['min'] && ! empty( $tier['phone'] ) ) {
					return preg_replace( '/[^0-9]/', '', $tier['phone'] );
				}
			}
		}

		// Country routing
		$country = $this->detect_country();
		if ( $country ) {
			$country_routing = json_decode( get_option( self::OPT_COUNTRY_ROUTING, '{}' ), true ) ?: array();
			if ( isset( $country_routing[ $country ] ) ) {
				return preg_replace( '/[^0-9]/', '', $country_routing[ $country ] );
			}
		}

		// Primary
		return preg_replace( '/[^0-9]/', '', get_option( self::OPT_PHONE, '' ) );
	}

	// ── Business Hours ───────────────────────────────────────────────────────

	private function get_availability(): array {
		if ( ! (bool) get_option( self::OPT_HOURS_ENABLED, 0 ) ) {
			return array(
				'online'  => true,
				'label'   => null,
				'message' => null,
			);
		}

		// Holiday check
		$holiday_dates = array_filter( array_map( 'trim', explode( ',', get_option( self::OPT_HOLIDAY_DATES, '' ) ) ) );
		$today_utc     = gmdate( 'Y-m-d' );
		if ( in_array( $today_utc, $holiday_dates, true ) ) {
			return array(
				'online'  => false,
				'label'   => get_option( self::OPT_HOLIDAY_LABEL, __( 'Holiday — leave a message', 'gt-bogo-engine' ) ),
				'message' => get_option( self::OPT_HOLIDAY_MSG, __( 'Hi, we are on holiday today. We will reply when we return.', 'gt-bogo-engine' ) ),
			);
		}

		$tz = get_option( self::OPT_HOURS_TZ, 'UTC' );
		try {
			$dt = new \DateTime( 'now', new \DateTimeZone( $tz ) );
		} catch ( \Exception $e ) {
			$dt = new \DateTime( 'now', new \DateTimeZone( 'UTC' ) );
		}

		$current_day  = (int) $dt->format( 'N' ); // 1=Mon, 7=Sun
		$current_time = $dt->format( 'H:i' );
		$open_days    = array_filter( array_map( 'intval', explode( ',', get_option( self::OPT_HOURS_DAYS, '1,2,3,4,5' ) ) ) );
		$open_time    = get_option( self::OPT_HOURS_OPEN, '09:00' );
		$close_time   = get_option( self::OPT_HOURS_CLOSE, '18:00' );
		$reply_in     = get_option( self::OPT_HOURS_REPLY, '24 hours' );

		$is_open = in_array( $current_day, $open_days, true )
			&& $current_time >= $open_time
			&& $current_time < $close_time;

		$offline_label = get_option(
			self::OPT_LABEL_OFFLINE,
			// translators: %s and %d are replaced with dynamic values.
			sprintf( __( 'Leave a message — we reply within %s', 'gt-bogo-engine' ), $reply_in )
		);

		return array(
			'online'  => $is_open,
			'label'   => $is_open ? null : $offline_label,
			'message' => $is_open ? null : sprintf(
				// translators: %s and %d are replaced with dynamic values.
				__( 'Hi, our team is currently offline. We reply within %s. How can we help?', 'gt-bogo-engine' ),
				$reply_in
			),
		);
	}

	// ── Message Builder ──────────────────────────────────────────────────────

	private function build_message( array $availability ): string {
		// Offline override
		if ( ! $availability['online'] && $availability['message'] ) {
			return $availability['message'];
		}

		$store      = get_bloginfo( 'name' );
		$cart_total = function_exists( 'WC' ) && WC()->cart
			? wp_strip_all_tags( wc_price( WC()->cart->get_cart_contents_total() ) )
			: '';
		$item_count = function_exists( 'WC' ) && WC()->cart
			? (int) WC()->cart->get_cart_contents_count()
			: 0;

		// Customer name for logged-in users
		$first_name = '';
		if ( is_user_logged_in() ) {
			$user       = wp_get_current_user();
			$first_name = $user->first_name ?: $user->display_name;
		}

		// Archetype-based template selection
		$archetype = 'universal';
		$intent    = 0;
		if ( class_exists( 'GT_BOGO_Signal_Bus' ) ) {
			$intent  = (float) GT_BOGO_Signal_Bus::get( 'behavioral_intent', 0 );
			$ltv     = (float) GT_BOGO_Signal_Bus::get( 'ltv_score', 0 );
			$at_risk = (float) GT_BOGO_Signal_Bus::get( 'price_sensitivity_score', 0 );
			if ( $ltv >= 4 ) {
				$archetype = 'vip';
			} elseif ( $at_risk >= 3 ) {
				$archetype = 'price_sensitive';
			} elseif ( $intent >= 3 ) {
				$archetype = 'high_intent';
			}
		}

		$greeting = $first_name
			// translators: %s and %d are replaced with dynamic values.
			? sprintf( __( 'Hi, I\'m %s.', 'gt-bogo-engine' ), $first_name )
			: __( 'Hi,', 'gt-bogo-engine' );

		// Base message by archetype
		$templates = array(
			'vip'             => __( 'I\'m a returning customer and I have a question about my order.', 'gt-bogo-engine' ),
			'high_intent'     => __( 'I am ready to complete my purchase and would like to confirm a deal.', 'gt-bogo-engine' ),
			'price_sensitive' => __( 'I\'m considering this purchase. Are there any current promotions I can use?', 'gt-bogo-engine' ),
			'universal'       => __( 'I have a question about my cart.', 'gt-bogo-engine' ),
		);
		$base      = $templates[ $archetype ] ?? $templates['universal'];

		// Cart context
		$cart_context = '';
		if ( $item_count > 0 && $cart_total ) {
			$cart_context = sprintf(
				/* translators: 1: item count, 2: cart total */                __( 'My cart has %1$d item(s) totalling %2$s.', 'gt-bogo-engine' ),
				$item_count,
				$cart_total
			);
		}

		// Deal context
		$deal_context = '';
		$pending      = function_exists( 'WC' ) && WC()->session
			? WC()->session->get( 'gtbogo_pending_trigger', null )
			: null;
		if ( $pending && ! empty( $pending['copy']['headline'] ) ) {
			$deal_context = $pending['copy']['headline'];
		}

		// Assemble
		$parts    = array_filter( array( $greeting, $base, $cart_context, $deal_context ) );
		$message  = implode( ' ', $parts );
		$message .= ' ' . home_url();

		return $message;
	}

	// ── Frequency Cap ────────────────────────────────────────────────────────

	private function get_user_key(): string {
		if ( is_user_logged_in() ) {
			return 'u' . get_current_user_id();
		}
		return 's' . substr( md5( sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ?? 'x' ) ) ), 0, 12 );
	}

	private function is_frequency_capped(): bool {
		$key = $this->get_user_key();
		// Click cooldown
		$cooldown = (int) get_option( self::OPT_COOLDOWN_HRS, 24 );
		if ( $cooldown > 0 && get_transient( self::TRANSIENT_CLICK . $key ) ) {
			return true;
		}
		// Daily impression limit
		$max_impr = (int) get_option( self::OPT_MAX_IMPR, 3 );
		$today    = gmdate( 'Ymd' );
		$impr_key = self::TRANSIENT_IMPR . $key . '_' . $today;
		$count    = (int) get_transient( $impr_key );
		return $max_impr > 0 && $count >= $max_impr;
	}

	private function record_impression(): void {
		$key      = $this->get_user_key();
		$today    = gmdate( 'Ymd' );
		$impr_key = self::TRANSIENT_IMPR . $key . '_' . $today;
		$count    = (int) get_transient( $impr_key );
		set_transient( $impr_key, $count + 1, DAY_IN_SECONDS );
	}

	// ── AJAX Tracking ────────────────────────────────────────────────────────

	public static function ajax_track_click(): void {
		if ( class_exists( 'GT_BOGO_Rate_Limiter' ) && ! GT_BOGO_Rate_Limiter::check( 'wa_click' ) ) {
			wp_send_json_error( array( 'code' => 'rate_limited' ), 429 );
			return;
		}
		if ( ! check_ajax_referer( 'gtbogo_wa_nonce', 'nonce', false ) ) {
			wp_send_json_error( 'invalid_nonce' );
			return;
		}
		$customer_id = is_user_logged_in() ? get_current_user_id() : 0;
		$rule_id     = absint( $_POST['rule_id'] ?? 0 );

		// Record to Outcome Capture
		if ( class_exists( 'GT_BOGO_Outcome_Capture' ) ) {
			GT_BOGO_Outcome_Capture::record_event(
				$customer_id,
				$rule_id,
				'accepted',
				function_exists( 'WC' ) && WC()->cart ? (float) WC()->cart->get_cart_contents_total() : 0,
				0,
				'whatsapp',
				'treatment',
				array(
					'trigger'   => 'whatsapp_click',
					'archetype' => sanitize_key( $_POST['archetype'] ?? 'universal' ),
				)
			);
		}

		// Set cooldown transient
		$key      = is_user_logged_in()
			? 'u' . $customer_id
			: 's' . substr( md5( sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ?? 'x' ) ) ), 0, 12 );
		$cooldown = (int) get_option( self::OPT_COOLDOWN_HRS, 24 );
		if ( $cooldown > 0 ) {
			set_transient( self::TRANSIENT_CLICK . $key, 1, $cooldown * HOUR_IN_SECONDS );
		}

		// Mark order as WhatsApp-assisted in session
		if ( function_exists( 'WC' ) && WC()->session ) {
			WC()->session->set( 'gtbogo_wa_assisted', 1 );
		}

		// Write intent signal
		self::write_signal( $customer_id );

		wp_send_json_success( array( 'tracked' => true ) );
	}

	public static function ajax_track_dismiss(): void {
		if ( class_exists( 'GT_BOGO_Rate_Limiter' ) && ! GT_BOGO_Rate_Limiter::check( 'wa_dismiss' ) ) {
			wp_send_json_error( array( 'code' => 'rate_limited' ), 429 );
			return;
		}
		check_ajax_referer( 'gtbogo_wa_nonce', 'nonce' );
		// Short suppress: 30min session suppress on dismiss
		$key = is_user_logged_in()
			? 'u' . get_current_user_id()
			: 's' . substr( md5( sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ?? 'x' ) ) ), 0, 12 );
		set_transient( self::TRANSIENT_CLICK . $key . '_dismiss', 1, 30 * MINUTE_IN_SECONDS );
		wp_send_json_success();
	}

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

	public function enqueue(): void {
		// All JS inline via wp_footer — no external file dependency
	}

	// ── Render ───────────────────────────────────────────────────────────────

	public function render(): void {
		$phone = $this->get_routed_phone();
		if ( empty( $phone ) ) {
			return;
		}

		$avail      = $this->get_availability();
		$message    = $this->build_message( $avail );
		$wa_url     = 'https://wa.me/' . esc_attr( $phone ) . '?text=' . rawurlencode( $message );
		$base_label = get_option( self::OPT_LABEL, __( 'Chat on WhatsApp', 'gt-bogo-engine' ) );
		$label      = ( ! $avail['online'] && $avail['label'] ) ? $avail['label'] : $base_label;
		$display    = sanitize_key( get_option( self::OPT_DISPLAY_MODE, 'floating' ) );
		$intensity  = $this->intensity();
		$anim       = $this->anim();
		$speed      = esc_attr( $anim['speed_token'] );
		$ease       = esc_attr( $anim['ease_token'] );
		$scroll_pct = max( 0, min( 100, (int) get_option( self::OPT_SCROLL_PCT, 0 ) ) );
		$delay_secs = max( 0, min( 30, (int) get_option( self::OPT_DELAY_SECS, 2 ) ) );
		$cfg        = $this->cfg();
		$style_attr = class_exists( 'GT_BOGO_Superpower_Theme_Intelligence' )
			? GT_BOGO_Superpower_Theme_Intelligence::style_attr( $cfg )
			: '';

		// Pending deal badge
		$pending  = function_exists( 'WC' ) && WC()->session
			? WC()->session->get( 'gtbogo_pending_trigger', null )
			: null;
		$has_deal = ! empty( $pending );

		// Signal Bus context for JS
		$intent    = 0;
		$archetype = 'universal';
		if ( class_exists( 'GT_BOGO_Signal_Bus' ) ) {
			$intent = (float) GT_BOGO_Signal_Bus::get( 'behavioral_intent', 0 );
		}

		$rule_id = $has_deal ? (int) ( $pending['rule_id'] ?? 0 ) : 0;

		$this->record_impression();

		// Icon SVG (WhatsApp official mark)
		$icon = '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" focusable="false" width="1.3em" height="1.3em"><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.05.0.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-.347z"/><path d="M11.946 0C5.342 0 0 5.342 0 11.946c0 2.1.553 4.159 1.602 5.973L0 24l6.303-1.578A11.91 11.91 0 0011.946 24C18.55 24 24 18.658 24 12.054 24 5.45 18.55.108 11.946.108L11.946 0zm0 21.818a9.829 9.829 0 01-5.043-1.388l-.362-.214-3.742.936.991-3.644-.235-.374a9.829 9.829 0 01-1.518-5.188C1.901 6.497 6.497 1.9 11.946 1.9c2.64 0 5.12 1.029 6.985 2.893a9.853 9.853 0 012.893 6.985c0 5.449-4.596 10.04-9.878 10.04z"/></svg>';

		$is_floating = $display === 'floating';
		$is_sticky   = $display === 'sticky';

		$show_label = $intensity !== 'subtle';
		$show_badge = $has_deal && $intensity === 'bold';
		$show_pulse = $has_deal && $intensity === 'bold' && $anim['use_gamification'];
		$is_online  = $avail['online'];

		$nonce = wp_create_nonce( 'gtbogo_wa_nonce' );
		?>
		<style id="gtbogo-wa-styles">
		.gtbogo-wa-wrap{
			position:<?php echo $is_floating ? 'fixed' : 'static'; ?>;
			<?php
			if ( $is_floating ) :
				?>
				bottom:var(--gtbogo-sp-pad-v,20px);right:var(--gtbogo-sp-pad-h,20px);z-index:9990;<?php endif; ?>
			<?php
			if ( $is_sticky ) :
				?>
				position:sticky;bottom:0;left:0;right:0;width:100%;z-index:9990;<?php endif; ?>
			opacity:0;pointer-events:none;
			transition:opacity <?php echo esc_attr( $speed ); ?> <?php echo esc_attr( $ease ); ?>,transform <?php echo esc_attr( $speed ); ?> <?php echo esc_attr( $ease ); ?>;
			<?php
			if ( $is_floating ) :
				?>
				transform:translateX(16px);<?php endif; ?>
			<?php
			if ( $is_sticky ) :
				?>
				transform:translateY(100%);<?php endif; ?>
		}
		.gtbogo-wa-wrap.is-visible{opacity:1;pointer-events:auto;
		<?php
		if ( $is_floating ) :
			?>
			transform:translateX(0);<?php endif; ?>
			<?php
			if ( $is_sticky ) :
				?>
			transform:translateY(0);<?php endif; ?>}
		.gtbogo-wa-btn{
			display:inline-flex;align-items:center;gap:var(--gtbogo-sp-gap,8px);
			padding:var(--gtbogo-sp-pad-v,12px) var(--gtbogo-sp-pad-h,18px);
			background:var(--gtbogo-wa-green,#25D366);color:var(--gtbogo-wa-text,rgba(255,255,255,0.97));border-radius:<?php echo $is_sticky ? '0' : '999px'; ?>;
			font-family:inherit;font-size:var(--gtbogo-sp-fs-base,0.9em);font-weight:var(--gtbogo-sp-fw-ui,600);
			text-decoration:none;border:none;cursor:pointer;
			min-height:var(--gtbogo-sp-touch-target,44px);min-width:var(--gtbogo-sp-touch-target,44px);
			box-shadow:var(--gtbogo-sp-shadow,0 2px 12px rgba(0,0,0,0.18));
			transition:opacity <?php echo esc_attr( $speed ); ?> <?php echo esc_attr( $ease ); ?>,transform <?php echo esc_attr( $speed ); ?> <?php echo esc_attr( $ease ); ?>;
			position:relative;justify-content:center;
			<?php
			if ( $is_sticky ) :
				?>
				width:100%;border-radius:0;<?php endif; ?>
		}
		.gtbogo-wa-btn:hover{opacity:0.92;
		<?php
		if ( $is_floating ) :
			?>
			transform:translateY(-2px) scale(1.03);box-shadow:var(--gtbogo-sp-shadow,0 6px 20px rgba(0,0,0,0.28));<?php endif; ?>}
		.gtbogo-wa-btn:focus-visible{outline:2px solid #fff;outline-offset:2px;}
		.gtbogo-wa-label{white-space:nowrap;line-height:var(--gtbogo-sp-lh-ui,1.4);}
		.gtbogo-wa-sub{font-size:var(--gtbogo-sp-fs-sm,0.78em);opacity:var(--gtbogo-sp-opacity-secondary,0.72);display:block;line-height:var(--gtbogo-sp-lh-ui,1.4);letter-spacing:var(--gtbogo-sp-tracking,0.01em);}
		.gtbogo-wa-badge{
			position:absolute;top:-6px;right:-6px;
			background:var(--gtbogo-sp-accent,#E10000);color:rgba(255,255,255,0.95);
			border-radius:var(--gtbogo-sp-radius-pill,999px);
			font-size:var(--gtbogo-sp-fs-xs,0.65em);font-weight:var(--gtbogo-sp-fw-ui,700);
			min-width:20px;height:20px;display:flex;align-items:center;justify-content:center;
			padding:0 var(--gtbogo-sp-pad-xs,4px);
			border:2px solid var(--gtbogo-sp-badge-border,rgba(255,255,255,0.9));
			box-shadow:0 1px 4px rgba(0,0,0,0.25);
		}
		.gtbogo-wa-status{
			width:10px;height:10px;border-radius:50%;flex-shrink:0;
			background:<?php echo $is_online ? 'rgba(255,255,255,0.95)' : 'rgba(255,255,255,0.35)'; ?>;
			box-shadow:<?php echo $is_online ? '0 0 0 2px rgba(255,255,255,0.3)' : 'none'; ?>;
		}
		.gtbogo-wa-dismiss{
			position:absolute;
			top:calc(-1 * var(--gtbogo-sp-pad-dismiss,8px));
			right:calc(-1 * var(--gtbogo-sp-pad-dismiss,8px));
			background:rgba(0,0,0,0.45);
			border:1px solid rgba(255,255,255,0.15);
			border-radius:50%;
			min-width:var(--gtbogo-sp-touch-target,44px);
			min-height:var(--gtbogo-sp-touch-target,44px);
			cursor:pointer;
			color:rgba(255,255,255,0.85);
			font-size:var(--gtbogo-sp-fs-base,0.9em);
			display:flex;align-items:center;justify-content:center;
			transition:background var(--gtbogo-sp-duration-subtle,200ms) ease,
						border-color var(--gtbogo-sp-duration-subtle,200ms) ease,
						color var(--gtbogo-sp-duration-subtle,200ms) ease;
			line-height:1;
			backdrop-filter:blur(4px);
		}
		.gtbogo-wa-dismiss:hover{
			background:rgba(0,0,0,0.7);
			border-color:rgba(255,255,255,0.3);
			color:rgba(255,255,255,0.95);
		}
		.gtbogo-wa-dismiss:focus-visible{
			outline:2px solid var(--gtbogo-sp-accent,#25D366);
			outline-offset:2px;
		}
		<?php if ( $show_pulse ) : ?>
		@keyframes gtbogo-wa-pulse{0%,100%{box-shadow:0 0 0 0 rgba(37,211,102,0.5)}50%{box-shadow:0 0 0 10px rgba(37,211,102,0)}}
		.gtbogo-wa-btn{animation:gtbogo-wa-pulse 2s ease infinite;}
		<?php endif; ?>
		<?php if ( $is_sticky ) : ?>
		.gtbogo-wa-wrap{display:flex;align-items:center;justify-content:center;background:var(--gtbogo-wa-green,#25D366);}
		<?php endif; ?>
		@media(max-width:480px){.gtbogo-wa-wrap{<?php echo $is_floating ? 'bottom:var(--gtbogo-sp-pad-v,12px);right:var(--gtbogo-sp-pad-h,12px);' : ''; ?>}}
		@media(prefers-reduced-motion:reduce){.gtbogo-wa-wrap,.gtbogo-wa-btn{transition:none!important;animation:none!important;}}
		</style>

		<div id="gtbogo-wa-wrap"
			class="gtbogo-wa-wrap"
			role="complementary"
			aria-label="<?php esc_attr_e( 'WhatsApp support', 'gt-bogo-engine' ); ?>"
			<?php echo $style_attr ? 'data-sp-style="' . esc_attr( $style_attr ) . '"' : ''; ?>
		>
			<?php if ( $is_floating ) : ?>
			<button class="gtbogo-wa-dismiss"
					id="gtbogo-wa-dismiss"
					aria-label="<?php esc_attr_e( 'Dismiss WhatsApp button', 'gt-bogo-engine' ); ?>"
					title="<?php esc_attr_e( 'Dismiss', 'gt-bogo-engine' ); ?>">×</button>
			<?php endif; ?>

			<a href="<?php echo esc_url( $wa_url ); ?>"
				class="gtbogo-wa-btn"
				id="gtbogo-wa-btn"
				target="_blank"
				rel="noopener noreferrer"
				aria-label="<?php echo esc_attr( $label ); ?>"
				data-rule-id="<?php echo esc_attr( $rule_id ); ?>"
				data-archetype="<?php echo esc_attr( $archetype ); ?>"
			>
				<?php if ( $show_badge ) : ?>
				<span class="gtbogo-wa-badge" aria-hidden="true">1</span>
				<?php endif; ?>
				<?php echo $icon; // phpcs:ignore WordPress.Security.EscapeOutput ?>
				<?php if ( $show_label ) : ?>
				<span class="gtbogo-wa-label">
					<?php echo esc_html( $label ); ?>
					<?php if ( $is_floating && $show_label ) : ?>
					<span class="gtbogo-wa-status" aria-hidden="true"></span>
					<?php endif; ?>
					<?php if ( $is_sticky && ! $is_online ) : ?>
					<span class="gtbogo-wa-sub"><?php echo esc_html( $avail['label'] ?: '' ); ?></span>
					<?php endif; ?>
				</span>
				<?php endif; ?>
			</a>
		</div>

		<script id="gtbogo-wa-js">
		(function(){
			var wrap       = document.getElementById('gtbogo-wa-wrap');
			var btn        = document.getElementById('gtbogo-wa-btn');
			var dismissBtn = document.getElementById('gtbogo-wa-dismiss');
			if(!wrap || !btn) return;

			var ajaxUrl  = <?php echo wp_json_encode( admin_url( 'admin-ajax.php' ) ); ?>;
			var nonce    = <?php echo wp_json_encode( $nonce ); ?>;
			var scrollPct= <?php echo (int) $scroll_pct; ?>;
			var delaySec = <?php echo (int) $delay_secs * 1000; ?>;
			var shown    = false;

			function show(){
				if(shown) return;
				shown = true;
				wrap.classList.add('is-visible');
			}

			function triggerShow(){
				if(delaySec > 0){
					setTimeout(function(){ checkScroll() || show(); }, delaySec);
				} else {
					checkScroll() || show();
				}
			}

			function checkScroll(){
				if(scrollPct <= 0){ show(); return true; }
				var pct = (window.scrollY / (document.body.scrollHeight - window.innerHeight || 1)) * 100;
				if(pct >= scrollPct){ show(); return true; }
				return false;
			}

			if(scrollPct > 0){
				window.addEventListener('scroll', function(){ if(!shown) checkScroll(); }, {passive:true});
			}
			triggerShow();

			// Click tracking
			btn.addEventListener('click', function(){
				var body = new FormData();
				body.append('action','gtbogo_wa_click');
				body.append('nonce', nonce);
				body.append('rule_id', btn.dataset.ruleId || '0');
				body.append('archetype', btn.dataset.archetype || 'universal');
				navigator.sendBeacon ? navigator.sendBeacon(ajaxUrl, body)
					: fetch(ajaxUrl,{method:'POST',body:body,credentials:'same-origin'}).catch(function(){});
			});

			// Dismiss
			if(dismissBtn){
				dismissBtn.addEventListener('click', function(e){
					e.preventDefault(); e.stopPropagation();
					wrap.classList.remove('is-visible');
					var b = new FormData();
					b.append('action','gtbogo_wa_dismiss');
					b.append('nonce',nonce);
					navigator.sendBeacon ? navigator.sendBeacon(ajaxUrl, b) : fetch(ajaxUrl,{method:'POST',body:b,credentials:'same-origin'}).catch(function(){});
				});
			}

			// Keyboard: Escape dismisses
			document.addEventListener('keydown', function(e){
				if(e.key === 'Escape' && wrap.classList.contains('is-visible')) wrap.classList.remove('is-visible');
			});
		}());
		</script>
		<?php
	}
}
