<?php
/**
 * Free frontend widgets: sticky cart and WhatsApp contact button.
 *
 * @package DreamFast_CF
 */

namespace DreamFast\CommerceFloat;

defined( 'ABSPATH' ) || exit;

/**
 * Class Frontend
 */
class Frontend {

	/**
	 * Singleton instance.
	 *
	 * @var Frontend|null
	 */
	private static $instance = null;

	/**
	 * Get singleton instance.
	 *
	 * @return Frontend
	 */
	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 * Register frontend hooks.
	 */
	public function init() {
		add_action( 'wp_enqueue_scripts', array( $this, 'register_assets' ), 5 );
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ), 20 );
		add_action( 'wp_footer', array( $this, 'render_widgets' ), 5 );
	}

	/**
	 * Register scripts and styles.
	 */
	public function register_assets() {
		wp_register_style( 'dreamfast-cf-frontend', DREAMFAST_CF_URL . 'assets/css/frontend.css', array(), DREAMFAST_CF_VERSION );
		wp_register_script( 'dreamfast-cf-frontend', DREAMFAST_CF_URL . 'assets/js/frontend.js', array(), DREAMFAST_CF_VERSION, true );
	}

	/**
	 * Enqueue assets only when a free widget is visible.
	 */
	public function enqueue_assets() {
		$show_cart    = Settings::should_show_sticky_cart();
		$show_contact = Settings::should_show_contact();

		if ( ! $show_cart && ! $show_contact ) {
			return;
		}

		wp_enqueue_style( 'dreamfast-cf-frontend' );
		wp_enqueue_script( 'dreamfast-cf-frontend' );
		wp_add_inline_style( 'dreamfast-cf-frontend', ':root{' . Settings::get_css_vars() . '}' );

		$config = array(
			'showCart'      => $show_cart,
			'showContact'   => $show_contact,
			'cartSelectors' => $show_cart ? $this->get_cart_button_selectors() : array(),
		);

		/**
		 * Filter the configuration passed to the frontend script.
		 *
		 * @since 1.1.0
		 *
		 * @param array<string, mixed> $config Data exposed as window.dreamfastCfConfig.
		 */
		$filtered = apply_filters( 'dreamfast_cf_frontend_config', $config );
		$config   = is_array( $filtered ) ? $filtered : $config;

		wp_localize_script( 'dreamfast-cf-frontend', 'dreamfastCfConfig', $config );
	}

	/**
	 * Get filtered selectors for the original Add to Cart button.
	 *
	 * @return array<int, string>
	 */
	private function get_cart_button_selectors() {
		$selectors = array(
			'form.cart .single_add_to_cart_button',
			'.entry-summary .single_add_to_cart_button',
			'.single_add_to_cart_button',
			'button[name="add-to-cart"]',
		);

		/**
		 * Filter the original Add to Cart button selectors.
		 *
		 * @param array<int, string> $selectors CSS selectors.
		 */
		$filtered = apply_filters( 'dreamfast_cf_cart_button_selectors', $selectors );
		if ( ! is_array( $filtered ) ) {
			$filtered = $selectors;
		}

		$clean = array();
		foreach ( $filtered as $selector ) {
			if ( ! is_string( $selector ) ) {
				continue;
			}

			$selector = trim( wp_strip_all_tags( $selector ) );
			if ( '' === $selector || strlen( $selector ) > 160 || preg_match( '/[\x00-\x1F\x7F]/', $selector ) ) {
				continue;
			}

			$clean[] = $selector;
		}

		return array_values( array_unique( ! empty( $clean ) ? $clean : $selectors ) );
	}

	/**
	 * Render visible widgets.
	 */
	public function render_widgets() {
		if ( Settings::should_show_sticky_cart() ) {
			$this->render_sticky_cart();
		}

		if ( Settings::should_show_contact() ) {
			$this->render_contact_widget();
		}
	}

	/**
	 * Render the sticky cart.
	 */
	private function render_sticky_cart() {
		global $product;

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

		$image_id = $product->get_image_id();

		$args = array(
			'image_url'      => $image_id ? wp_get_attachment_image_url( $image_id, 'woocommerce_thumbnail' ) : wc_placeholder_img_src( 'woocommerce_thumbnail' ),
			'price_html'     => $product->get_price_html(),
			'is_purchasable' => $product->is_purchasable() && $product->is_in_stock(),
			'product_type'   => $product->get_type(),
		);

		/**
		 * Filter the sticky cart bar template data before it is rendered.
		 *
		 * @since 1.1.0
		 *
		 * @param array<string, mixed> $args    Template data: image_url, price_html,
		 *                                      is_purchasable, product_type.
		 * @param \WC_Product          $product Current product.
		 */
		$filtered = apply_filters( 'dreamfast_cf_sticky_cart_args', $args, $product );
		$args     = is_array( $filtered ) ? $filtered : $args;

		$image_url      = isset( $args['image_url'] ) ? $args['image_url'] : '';
		$price_html     = isset( $args['price_html'] ) ? $args['price_html'] : '';
		$is_purchasable = ! empty( $args['is_purchasable'] );
		$product_type   = isset( $args['product_type'] ) ? $args['product_type'] : '';

		ob_start();
		include DREAMFAST_CF_PATH . 'templates/sticky-cart-bar.php';
		$html = ob_get_clean();

		/**
		 * Filter the full sticky cart bar markup before output.
		 *
		 * Returned markup is printed as-is, so it must already be safe HTML.
		 * Return an empty string to suppress the bar.
		 *
		 * @since 1.1.0
		 *
		 * @param string               $html    Sticky cart bar markup.
		 * @param array<string, mixed> $args    Template data used to build the markup.
		 * @param \WC_Product          $product Current product.
		 */
		$filtered = apply_filters( 'dreamfast_cf_sticky_cart_html', $html, $args, $product );
		$html     = is_scalar( $filtered ) ? (string) $filtered : $html;

		if ( '' === $html ) {
			return;
		}

		/**
		 * Fires immediately before the sticky cart bar markup is printed.
		 *
		 * @since 1.1.0
		 *
		 * @param array<string, mixed> $args    Template data used to build the markup.
		 * @param \WC_Product          $product Current product.
		 */
		do_action( 'dreamfast_cf_before_sticky_cart', $args, $product );

		echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Markup is escaped in the template; third-party filters are responsible for their own output.

		/**
		 * Fires immediately after the sticky cart bar markup is printed.
		 *
		 * @since 1.1.0
		 *
		 * @param array<string, mixed> $args    Template data used to build the markup.
		 * @param \WC_Product          $product Current product.
		 */
		do_action( 'dreamfast_cf_after_sticky_cart', $args, $product );
	}

	/**
	 * Render the direct WhatsApp contact button.
	 */
	private function render_contact_widget() {
		$args = array(
			'position'        => sanitize_key( (string) Settings::get( 'contact_position', 'bottom-right' ) ),
			'whatsapp'        => Settings::get_whatsapp_url(),
			'tooltip_enabled' => (bool) Settings::get( 'contact_tooltip_enabled', true ),
			'tooltip_text'    => trim( (string) Settings::get( 'contact_tooltip_text', __( 'Need help?', 'dreamfast-commerce-float' ) ) ),
		);

		/**
		 * Filter the contact widget template data before it is rendered.
		 *
		 * @since 1.1.0
		 *
		 * @param array<string, mixed> $args Template data: position, whatsapp,
		 *                                   tooltip_enabled, tooltip_text.
		 */
		$filtered = apply_filters( 'dreamfast_cf_contact_args', $args );
		$args     = is_array( $filtered ) ? $filtered : $args;

		$position        = isset( $args['position'] ) ? $args['position'] : 'bottom-right';
		$whatsapp        = isset( $args['whatsapp'] ) ? $args['whatsapp'] : '';
		$tooltip_enabled = ! empty( $args['tooltip_enabled'] );
		$tooltip_text    = isset( $args['tooltip_text'] ) ? $args['tooltip_text'] : '';

		ob_start();
		include DREAMFAST_CF_PATH . 'templates/contact-widget.php';
		$html = ob_get_clean();

		/**
		 * Filter the full contact widget markup before output.
		 *
		 * Returned markup is printed as-is, so it must already be safe HTML.
		 * Return an empty string to suppress the button.
		 *
		 * @since 1.1.0
		 *
		 * @param string               $html Contact widget markup.
		 * @param array<string, mixed> $args Template data used to build the markup.
		 */
		$filtered = apply_filters( 'dreamfast_cf_contact_html', $html, $args );
		$html     = is_scalar( $filtered ) ? (string) $filtered : $html;

		if ( '' === $html ) {
			return;
		}

		/**
		 * Fires immediately before the contact widget markup is printed.
		 *
		 * @since 1.1.0
		 *
		 * @param array<string, mixed> $args Template data used to build the markup.
		 */
		do_action( 'dreamfast_cf_before_contact', $args );

		echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Markup is escaped in the template; third-party filters are responsible for their own output.

		/**
		 * Fires immediately after the contact widget markup is printed.
		 *
		 * @since 1.1.0
		 *
		 * @param array<string, mixed> $args Template data used to build the markup.
		 */
		do_action( 'dreamfast_cf_after_contact', $args );
	}
}
