<?php
/**
 * Elementor UGC Gallery widget.
 *
 * @package Ugcify\Elementor\Widgets
 */

namespace Ugcify\Elementor\Widgets;

use Elementor\Controls_Manager;
use Elementor\Widget_Base;
use Ugcify\Helpers\FeatureGate;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class UGCGalleryWidget
 */
class UGCGalleryWidget extends Widget_Base {
	/**
	 * Get widget name.
	 *
	 * @return string
	 */
	public function get_name() {
		return 'ugcify_gallery';
	}

	/**
	 * Get widget title.
	 *
	 * @return string
	 */
	public function get_title() {
		return __( 'UGC Gallery', 'ugcify' );
	}

	/**
	 * Get widget icon.
	 *
	 * @return string
	 */
	public function get_icon() {
		return 'eicon-gallery-grid';
	}

	/**
	 * Get widget categories.
	 *
	 * @return array
	 */
	public function get_categories() {
		return array( 'general' );
	}

	/**
	 * Get widget keywords.
	 *
	 * @return array
	 */
	public function get_keywords() {
		return array(
			'ugcify',
			'reviews',
			'gallery',
			'woocommerce',
		);
	}

	/**
	 * Frontend stylesheet dependencies.
	 *
	 * @return array
	 */
	public function get_style_depends() {
		return array( 'ugcify-frontend' );
	}

	/**
	 * Frontend script dependencies.
	 *
	 * @return array
	 */
	public function get_script_depends() {
		return array( 'ugcify-frontend' );
	}

	/**
	 * Authoritative default settings for this widget.
	 *
	 * @return array
	 */
	public static function get_default_settings() {
		return array(
			'productId'               => '',
			'categories'              => array(),
			'tags'                    => array(),
			'blockTemplate'           => 'minimal_gallery',
			'minimalWidgetType'       => 'grid',
			'widgetType'              => 'grid',
			'gridStyle'               => 'masonry',
			'mediaMosaicStyle'        => 'grid',
			'columnsDesktop'          => '4',
			'gapSpacing'              => '16',
			'showHeaderTitle'         => true,
			'title'                   => 'Customers are saying',
			'titleFontWeight'         => '600',
			'titleFontSize'           => 'medium',
			'emptyReviewText'         => 'No customer review yet. Be the first to review!',
			'primaryColor'            => '#201CFE',
			'titleColor'              => '#000000',
			'bodyFontColor'           => '#444444',
			'cardBgColor'             => '#FFFFFF',
			'ratingColor'             => '#FFA800',
			'buttonTextColor'         => '#FFFFFF',
			'filterFillColor'         => '#FFFFFF',
			'filterStrokeColor'       => '#201CFE',
			'filterIconColor'         => '#292D32',
			'readMoreColor'           => '#000000',
			'loadMoreTextColor'       => '#201CFE',
			'loadMoreBgColor'         => '#FFFFFF',
			'loadMoreBorderColor'     => '#201CFE',
			'reviewerNameFormat'      => 'full',
			'reviewerNameFontSize'    => 'medium',
			'showCustomerAvatar'      => true,
			'showVerifiedCheck'       => true,
			'showInfluencerBadge'     => true,
			'reviewDateFormat'        => 'd M, Y',
			'starRatingSize'          => 'medium',
			'reviewTextSize'          => 'medium',
			'reviewTextLength'        => 'large',
			'reviewCardBorderRadius'  => '10',
			'testimonialQuoteSize'    => 'medium',
			'testimonialQuoteColor'   => '#322EFE',
			'testimonialQuoteOpacity' => '1',
			'reviewColumn'            => '3',
			'reviewsPerPage'          => '3',
			'showReviews'             => true,
			'showLoadMoreButton'      => true,
			'loadMoreTextSize'        => 'medium',
			'loadMoreBorderRadius'    => '10',
			'lazyLoadImages'          => true,
			'autoplayVideo'           => false,
			'enableLightbox'          => true,
			'showMediaCarousel'       => true,
			'mediaCarouselItemsToShow' => '10',
			'tagStyle'                => 'pulsing_dot',
			'directAddToCart'         => true,
			'enableUpvotes'           => false,
			'socialShareButtons'      => false,
			'customersAlsoBought'     => false,
			'showStories'             => true,
			'storiesTitle'            => 'Customer Stories',
			'storiesMaxCount'         => 8,
			'showAddYours'            => true,
			'showCommunity'           => true,
			'communityTitle'          => 'Community Reviews',
			'communitySubtitle'       => 'See what our customers are saying',
			'showShareBtn'            => true,
		);
	}

	/**
	 * Read a default setting without emitting an undefined array-key warning.
	 *
	 * @param array  $defaults Default settings.
	 * @param string $key      Setting key.
	 * @param mixed  $fallback Fallback value.
	 * @return mixed
	 */
	private static function get_default_setting( $defaults, $key, $fallback = null ) {
		return array_key_exists( $key, $defaults ) ? $defaults[ $key ] : $fallback;
	}

	/**
	 * Register controls.
	 *
	 * @return void
	 */
	protected function register_controls() {
		$this->register_review_filter_controls();
		$this->register_general_controls();
		$this->register_template_specific_controls();
		$this->register_header_controls();
		$this->register_color_style_controls();
		$this->register_review_section_controls();
		$this->register_media_behavior_controls();
		$this->register_action_controls();
	}

	/**
	 * Register review filters controls.
	 *
	 * @return void
	 */
	private function register_review_filter_controls() {
		$defaults = self::get_default_settings();

		$this->start_controls_section(
			'ugcify_review_filters',
			array(
				'label' => __( 'Review Filters', 'ugcify' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);

		if ( ! class_exists( 'WooCommerce' ) ) {
			$this->add_control(
				'woocommerce_missing_notice',
				array(
					'type'            => Controls_Manager::RAW_HTML,
					'raw'             => esc_html__( 'WooCommerce is required for product/category/tag filter controls.', 'ugcify' ),
					'content_classes' => 'elementor-panel-alert elementor-panel-alert-warning',
				)
			);
			$this->end_controls_section();
			return;
		}

		$this->add_control(
			'productId',
			array(
				'label'         => __( 'Product', 'ugcify' ),
				'type'          => Controls_Manager::SELECT2,
				'options'       => $this->get_product_options_for_control(),
				'default'       => self::get_default_setting( $defaults, 'productId' ),
				'label_block'   => true,
				'render_type'   => 'template',
				'select2options' => array(
					'ajax' => array(
						'url'      => $this->get_block_data_url(
							'block-data/products',
							array(
								'format' => 'select2',
								'limit'  => 20,
							)
						),
						'dataType' => 'json',
						'delay'    => 250,
						'cache'    => true,
					),
				),
				'description'   => __( 'Select one product. Leave empty to use taxonomy filters or current product context.', 'ugcify' ),
			)
		);

		$this->add_control(
			'categories',
			array(
				'label'         => __( 'Categories', 'ugcify' ),
				'type'          => Controls_Manager::SELECT2,
				'multiple'      => true,
				'options'       => $this->get_term_options_for_control( 'product_cat' ),
				'default'       => self::get_default_setting( $defaults, 'categories' ),
				'label_block'   => true,
				'render_type'   => 'template',
				'select2options' => array(
					'ajax' => array(
						'url'      => $this->get_block_data_url(
							'block-data/terms',
							array(
								'format'   => 'select2',
								'limit'    => 20,
								'taxonomy' => 'product_cat',
							)
						),
						'dataType' => 'json',
						'delay'    => 250,
						'cache'    => true,
					),
				),
			)
		);

		$this->add_control(
			'tags',
			array(
				'label'         => __( 'Tags', 'ugcify' ),
				'type'          => Controls_Manager::SELECT2,
				'multiple'      => true,
				'options'       => $this->get_term_options_for_control( 'product_tag' ),
				'default'       => self::get_default_setting( $defaults, 'tags' ),
				'label_block'   => true,
				'render_type'   => 'template',
				'select2options' => array(
					'ajax' => array(
						'url'      => $this->get_block_data_url(
							'block-data/terms',
							array(
								'format'   => 'select2',
								'limit'    => 20,
								'taxonomy' => 'product_tag',
							)
						),
						'dataType' => 'json',
						'delay'    => 250,
						'cache'    => true,
					),
				),
			)
		);

		$this->end_controls_section();
	}

	/**
	 * Register general controls.
	 *
	 * @return void
	 */
	private function register_general_controls() {
		$defaults = self::get_default_settings();
		$can_use_reels = FeatureGate::is_enabled( 'block_studio_reels' );
		$can_use_carousel = FeatureGate::is_enabled( 'block_studio_gallery' );
		$is_pro = (bool) apply_filters( 'ugcify_is_pro_active', false );
		$plan = (string) apply_filters( 'ugcify_license_plan', '' );
		$upgrade_url = esc_url( apply_filters( 'ugcify_upgrade_url', admin_url( 'admin.php?page=ugcify#/license' ) ) );

		$this->start_controls_section(
			'ugcify_general',
			array(
				'label' => __( 'Template', 'ugcify' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);

		$status_label = $is_pro ? __( 'Subscribed', 'ugcify' ) : __( 'Free Plan', 'ugcify' );
		if ( $is_pro && '' !== $plan ) {
			$status_label .= ' (' . $plan . ')';
		}

		$this->add_control(
			'subscription_status_notice',
			array(
				'type' => Controls_Manager::RAW_HTML,
				'raw'  => sprintf(
					'<div style="margin-bottom:10px;"><strong>%1$s</strong><br/>%2$s<br/><a href="%3$s" target="_blank" rel="noopener noreferrer">%4$s</a></div>',
					esc_html( $status_label ),
					esc_html( $is_pro ? __( 'Premium features available', 'ugcify' ) : __( 'Upgrade to unlock Reels and Carousel templates.', 'ugcify' ) ),
					esc_url( $upgrade_url ),
					esc_html__( 'Upgrade plan', 'ugcify' )
				),
			)
		);

		$this->add_control(
			'blockTemplate',
			array(
				'label'       => __( 'Apply Template', 'ugcify' ),
				'type'        => Controls_Manager::SELECT,
				'options'     => array_filter(
					array(
						'minimal_gallery' => __( 'Minimal Gallery', 'ugcify' ),
						'reels'           => $can_use_reels ? __( 'Reels', 'ugcify' ) : null,
						'carousel'        => $can_use_carousel ? __( 'Attachment Carousel Template', 'ugcify' ) : null,
						'card_carousel'   => $can_use_carousel ? __( 'Card Carousel', 'ugcify' ) : null,
						'media_mosaic'    => $can_use_carousel ? __( 'Media Mosaic', 'ugcify' ) : null,
						'testimonial_carousel' => $can_use_carousel ? __( 'Testimonial Carousel', 'ugcify' ) : null,
					)
				),
				'default'     => self::get_default_setting( $defaults, 'blockTemplate' ),
				'render_type' => 'template',
			)
		);

		if ( ! $can_use_reels || ! $can_use_carousel ) {
			$this->add_control(
				'template_lock_notice',
				array(
					'type' => Controls_Manager::RAW_HTML,
					'raw'  => '<div style="color:#757575;">' . esc_html__( 'Available only for subscribed users.', 'ugcify' ) . '</div>',
				)
			);
		}

		$this->add_control(
			'minimalWidgetType',
			array(
				'label'       => __( 'Widget Type', 'ugcify' ),
				'type'        => Controls_Manager::SELECT,
				'options'     => array(
					'grid'    => __( 'Grid', 'ugcify' ),
					'masonry' => __( 'Masonry', 'ugcify' ),
					'slider'  => __( 'Slider', 'ugcify' ),
				),
				'default'     => self::get_default_setting( $defaults, 'minimalWidgetType' ),
				'prefix_class' => 'ugcify-widget-type-',
				'render_type' => 'template',
				'condition'   => array(
					'blockTemplate' => 'minimal_gallery',
				),
			)
		);

		$this->end_controls_section();
	}

	/**
	 * Register template-specific controls.
	 *
	 * @return void
	 */
	private function register_template_specific_controls() {
		$defaults = self::get_default_settings();
		$gallery_templates = array( 'carousel', 'card_carousel', 'media_mosaic', 'testimonial_carousel' );

		$this->start_controls_section(
			'ugcify_reels_settings',
			array(
				'label'     => __( 'Reels', 'ugcify' ),
				'tab'       => Controls_Manager::TAB_CONTENT,
				'condition' => array(
					'blockTemplate' => 'reels',
				),
			)
		);

		$this->add_control( 'showStories', array( 'label' => __( 'Show Stories', 'ugcify' ), 'type' => Controls_Manager::SWITCHER, 'default' => self::get_default_setting( $defaults, 'showStories' ) ? 'yes' : '' ) );
		$this->add_control( 'storiesTitle', array( 'label' => __( 'Stories Title', 'ugcify' ), 'type' => Controls_Manager::TEXT, 'default' => self::get_default_setting( $defaults, 'storiesTitle' ) ) );
		$this->add_control( 'storiesMaxCount', array( 'label' => __( 'Stories Max Count', 'ugcify' ), 'type' => Controls_Manager::NUMBER, 'min' => 1, 'max' => 20, 'default' => absint( self::get_default_setting( $defaults, 'storiesMaxCount' ) ) ) );
		$this->add_control( 'showAddYours', array( 'label' => __( 'Show Add Yours', 'ugcify' ), 'type' => Controls_Manager::SWITCHER, 'default' => self::get_default_setting( $defaults, 'showAddYours' ) ? 'yes' : '' ) );
		$this->add_control( 'showCommunity', array( 'label' => __( 'Show Community', 'ugcify' ), 'type' => Controls_Manager::SWITCHER, 'default' => self::get_default_setting( $defaults, 'showCommunity' ) ? 'yes' : '' ) );
		$this->add_control( 'communityTitle', array( 'label' => __( 'Community Title', 'ugcify' ), 'type' => Controls_Manager::TEXT, 'default' => self::get_default_setting( $defaults, 'communityTitle' ) ) );
		$this->add_control( 'communitySubtitle', array( 'label' => __( 'Community Subtitle', 'ugcify' ), 'type' => Controls_Manager::TEXT, 'default' => self::get_default_setting( $defaults, 'communitySubtitle' ) ) );
		$this->add_control( 'showShareBtn', array( 'label' => __( 'Show Share Button', 'ugcify' ), 'type' => Controls_Manager::SWITCHER, 'default' => self::get_default_setting( $defaults, 'showShareBtn' ) ? 'yes' : '' ) );
		$this->end_controls_section();

		$this->start_controls_section(
			'ugcify_carousel_settings',
			array(
				'label'     => __( 'Media Carousel', 'ugcify' ),
				'tab'       => Controls_Manager::TAB_CONTENT,
				'condition' => array(
					'blockTemplate' => 'carousel',
				),
			)
		);
		$this->add_control( 'showMediaCarousel', array( 'label' => __( 'Show Carousel', 'ugcify' ), 'type' => Controls_Manager::SWITCHER, 'return_value' => 'yes', 'default' => self::get_default_setting( $defaults, 'showMediaCarousel' ) ? 'yes' : '', 'render_type' => 'template' ) );
		$this->add_control( 'mediaCarouselItemsToShow', array( 'label' => __( 'Items to Show', 'ugcify' ), 'type' => Controls_Manager::NUMBER, 'min' => 1, 'max' => 100, 'default' => absint( self::get_default_setting( $defaults, 'mediaCarouselItemsToShow' ) ), 'render_type' => 'template', 'condition' => array( 'showMediaCarousel' => 'yes' ) ) );
		$this->end_controls_section();
	}

	/**
	 * Register header controls.
	 *
	 * @return void
	 */
	private function register_header_controls() {
		$defaults = self::get_default_settings();

		$this->start_controls_section(
			'ugcify_header',
			array(
				'label' => __( 'Header Area', 'ugcify' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);

		$this->add_control(
			'showHeaderTitle',
			array(
				'label'       => __( 'Show Header Title', 'ugcify' ),
				'type'        => Controls_Manager::SWITCHER,
				'default'     => self::get_default_setting( $defaults, 'showHeaderTitle' ) ? 'yes' : '',
				'return_value' => 'yes',
				'render_type' => 'template',
			)
		);

		$this->add_control(
			'title',
			array(
				'label'       => __( 'Title', 'ugcify' ),
				'type'        => Controls_Manager::TEXT,
				'default'     => self::get_default_setting( $defaults, 'title' ),
				'render_type' => 'template',
			)
		);

		$this->add_control(
			'titleFontWeight',
			array(
				'label'       => __( 'Title Font Weight', 'ugcify' ),
				'type'        => Controls_Manager::SELECT,
				'options'     => array(
					'400' => '400',
					'500' => '500',
					'600' => '600',
					'700' => '700',
				),
				'default'     => self::get_default_setting( $defaults, 'titleFontWeight' ),
				'render_type' => 'template',
			)
		);

		$this->add_control(
			'titleFontSize',
			array(
				'label'       => __( 'Title Font Size', 'ugcify' ),
				'type'        => Controls_Manager::SELECT,
				'options'     => array(
					'small'  => __( 'Small', 'ugcify' ),
					'medium' => __( 'Medium', 'ugcify' ),
					'large'  => __( 'Large', 'ugcify' ),
				),
				'default'     => self::get_default_setting( $defaults, 'titleFontSize' ),
				'render_type' => 'template',
			)
		);

		$this->add_control(
			'emptyReviewText',
			array(
				'label'       => __( 'Empty Review Text', 'ugcify' ),
				'type'        => Controls_Manager::TEXT,
				'default'     => self::get_default_setting( $defaults, 'emptyReviewText' ),
				'render_type' => 'template',
			)
		);

		$this->end_controls_section();
	}

	/**
	 * Register color and style controls.
	 *
	 * @return void
	 */
	private function register_color_style_controls() {
		$defaults = self::get_default_settings();
		$gallery_templates = array( 'carousel', 'card_carousel', 'media_mosaic', 'testimonial_carousel' );

		$this->start_controls_section(
			'ugcify_colors_styles',
			array(
				'label' => __( 'Colors and Styles', 'ugcify' ),
				'tab'   => Controls_Manager::TAB_STYLE,
			)
		);

		$this->add_control(
			'primaryColor',
			array(
				'label'   => __( 'Primary Color', 'ugcify' ),
				'type'    => Controls_Manager::COLOR,
				'default' => self::get_default_setting( $defaults, 'primaryColor' ),
			)
		);

		$this->add_control(
			'titleColor',
			array(
				'label'   => __( 'Title Color', 'ugcify' ),
				'type'    => Controls_Manager::COLOR,
				'default' => self::get_default_setting( $defaults, 'titleColor' ),
			)
		);

		$this->add_control(
			'bodyFontColor',
			array(
				'label'   => __( 'Body Font Color', 'ugcify' ),
				'type'    => Controls_Manager::COLOR,
				'default' => self::get_default_setting( $defaults, 'bodyFontColor' ),
			)
		);

		$this->add_control(
			'cardBgColor',
			array(
				'label'   => __( 'Card Background Color', 'ugcify' ),
				'type'    => Controls_Manager::COLOR,
				'default' => self::get_default_setting( $defaults, 'cardBgColor' ),
			)
		);

		$this->add_control(
			'ratingColor',
			array(
				'label'   => __( 'Rating Color', 'ugcify' ),
				'type'    => Controls_Manager::COLOR,
				'default' => self::get_default_setting( $defaults, 'ratingColor' ),
			)
		);

		$this->add_control(
			'buttonTextColor',
			array(
				'label'   => __( 'Button Text Color', 'ugcify' ),
				'type'    => Controls_Manager::COLOR,
				'default' => self::get_default_setting( $defaults, 'buttonTextColor' ),
			)
		);

		$this->add_control(
			'filterFillColor',
			array(
				'label'   => __( 'Filter Fill Color', 'ugcify' ),
				'type'    => Controls_Manager::COLOR,
				'default' => self::get_default_setting( $defaults, 'filterFillColor' ),
			)
		);

		$this->add_control(
			'filterStrokeColor',
			array(
				'label'   => __( 'Filter Stroke Color', 'ugcify' ),
				'type'    => Controls_Manager::COLOR,
				'default' => self::get_default_setting( $defaults, 'filterStrokeColor' ),
			)
		);

		$this->add_control(
			'filterIconColor',
			array(
				'label'   => __( 'Filter Icon Color', 'ugcify' ),
				'type'    => Controls_Manager::COLOR,
				'default' => self::get_default_setting( $defaults, 'filterIconColor' ),
			)
		);

		$this->add_control(
			'readMoreColor',
			array(
				'label'   => __( 'Read More Color', 'ugcify' ),
				'type'    => Controls_Manager::COLOR,
				'default' => self::get_default_setting( $defaults, 'readMoreColor' ),
			)
		);

		$this->add_control(
			'loadMoreTextColor',
			array(
				'label'     => __( 'Load More Text Color', 'ugcify' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => self::get_default_setting( $defaults, 'loadMoreTextColor' ),
				'condition' => array(
					'blockTemplate' => $gallery_templates,
				),
			)
		);
		$this->add_control(
			'loadMoreBgColor',
			array(
				'label'     => __( 'Load More Background Color', 'ugcify' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => self::get_default_setting( $defaults, 'loadMoreBgColor' ),
				'condition' => array(
					'blockTemplate' => $gallery_templates,
				),
			)
		);
		$this->add_control(
			'loadMoreBorderColor',
			array(
				'label'     => __( 'Load More Border Color', 'ugcify' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => self::get_default_setting( $defaults, 'loadMoreBorderColor' ),
				'condition' => array(
					'blockTemplate' => $gallery_templates,
				),
			)
		);

		$this->end_controls_section();
	}

	/**
	 * Register media behavior controls.
	 *
	 * @return void
	 */
	private function register_media_behavior_controls() {
		$defaults = self::get_default_settings();
		$this->start_controls_section(
			'ugcify_media_behavior',
			array(
				'label' => __( 'Media Behavior', 'ugcify' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);
		$this->add_control( 'lazyLoadImages', array( 'label' => __( 'Lazy Load Images', 'ugcify' ), 'type' => Controls_Manager::SWITCHER, 'default' => self::get_default_setting( $defaults, 'lazyLoadImages' ) ? 'yes' : '' ) );
		$this->add_control( 'autoplayVideo', array( 'label' => __( 'Autoplay Video (Muted)', 'ugcify' ), 'type' => Controls_Manager::SWITCHER, 'default' => self::get_default_setting( $defaults, 'autoplayVideo' ) ? 'yes' : '' ) );
		$this->add_control( 'enableLightbox', array( 'label' => __( 'Enable Lightbox', 'ugcify' ), 'type' => Controls_Manager::SWITCHER, 'default' => self::get_default_setting( $defaults, 'enableLightbox' ) ? 'yes' : '' ) );
		$this->end_controls_section();
	}

	/**
	 * Register review section controls.
	 *
	 * @return void
	 */
	private function register_review_section_controls() {
		$defaults = self::get_default_settings();
		$gallery_templates = array( 'carousel', 'card_carousel', 'media_mosaic', 'testimonial_carousel' );

		$this->start_controls_section(
			'ugcify_review_section',
			array(
				'label' => __( 'Review Section', 'ugcify' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);

		$this->add_control(
			'mediaMosaicStyle',
			array(
				'label'       => __( 'Style', 'ugcify' ),
				'type'        => Controls_Manager::SELECT,
				'options'     => array(
					'grid'    => __( 'Grid', 'ugcify' ),
					'masonry' => __( 'Masonry', 'ugcify' ),
					'slider'  => __( 'Slider', 'ugcify' ),
				),
				'default'     => self::get_default_setting( $defaults, 'mediaMosaicStyle', 'grid' ),
				'render_type' => 'template',
				'condition'   => array(
					'blockTemplate' => 'media_mosaic',
				),
			)
		);

		$this->add_control(
			'reviewerNameFormat',
			array(
				'label'       => __( 'Reviewer Name Format', 'ugcify' ),
				'type'        => Controls_Manager::SELECT,
				'options'     => array(
					'full'               => __( 'Full', 'ugcify' ),
					'first_last_initial' => __( 'First + Last Initial', 'ugcify' ),
					'first_only'         => __( 'First Only', 'ugcify' ),
					'initials'           => __( 'Initials', 'ugcify' ),
				),
				'default'     => self::get_default_setting( $defaults, 'reviewerNameFormat' ),
				'render_type' => 'template',
			)
		);

		$this->add_control(
			'reviewerNameFontSize',
			array(
				'label'       => __( 'Reviewer Name Font Size', 'ugcify' ),
				'type'        => Controls_Manager::SELECT,
				'options'     => array(
					'small'  => __( 'Small', 'ugcify' ),
					'medium' => __( 'Medium', 'ugcify' ),
					'large'  => __( 'Large', 'ugcify' ),
				),
				'default'     => self::get_default_setting( $defaults, 'reviewerNameFontSize' ),
				'render_type' => 'template',
			)
		);

		$this->add_control(
			'showCustomerAvatar',
			array(
				'label'        => __( 'Show Customer Avatar', 'ugcify' ),
				'type'         => Controls_Manager::SWITCHER,
				'default'      => self::get_default_setting( $defaults, 'showCustomerAvatar' ) ? 'yes' : '',
				'return_value' => 'yes',
				'render_type'  => 'template',
				'condition'    => array(
					'blockTemplate' => 'media_mosaic',
				),
			)
		);

		$this->add_control(
			'testimonialQuoteSize',
			array(
				'label'       => __( 'Quote Icon Size', 'ugcify' ),
				'type'        => Controls_Manager::SELECT,
				'options'     => array(
					'small'  => __( 'Small', 'ugcify' ),
					'medium' => __( 'Medium', 'ugcify' ),
					'large'  => __( 'Large', 'ugcify' ),
				),
				'default'     => self::get_default_setting( $defaults, 'testimonialQuoteSize' ),
				'render_type' => 'template',
				'condition'   => array(
					'blockTemplate' => 'testimonial_carousel',
				),
			)
		);

		$this->add_control(
			'testimonialQuoteColor',
			array(
				'label'       => __( 'Quote Icon Color', 'ugcify' ),
				'type'        => Controls_Manager::COLOR,
				'default'     => self::get_default_setting( $defaults, 'testimonialQuoteColor' ),
				'render_type' => 'template',
				'condition'   => array(
					'blockTemplate' => 'testimonial_carousel',
				),
			)
		);

		$this->add_control(
			'testimonialQuoteOpacity',
			array(
				'label'       => __( 'Quote Icon Opacity', 'ugcify' ),
				'type'        => Controls_Manager::SLIDER,
				'size_units'  => array( '%' ),
				'range'       => array(
					'%' => array(
						'min'  => 0,
						'max'  => 100,
						'step' => 1,
					),
				),
				'default'     => array(
					'unit' => '%',
					'size' => 100,
				),
				'render_type' => 'template',
				'condition'   => array(
					'blockTemplate' => 'testimonial_carousel',
				),
			)
		);

		$this->add_control(
			'showVerifiedCheck',
			array(
				'label'        => __( 'Show Verified Check', 'ugcify' ),
				'type'         => Controls_Manager::SWITCHER,
				'default'      => self::get_default_setting( $defaults, 'showVerifiedCheck' ) ? 'yes' : '',
				'return_value' => 'yes',
				'render_type'  => 'template',
			)
		);

		$this->add_control(
			'reviewDateFormat',
			array(
				'label'       => __( 'Review Date Format', 'ugcify' ),
				'type'        => Controls_Manager::SELECT,
				'options'     => array(
					'd M, Y' => '12 Dec, 2025',
					'M d, Y' => 'Dec 12, 2025',
					'd/m/Y'  => '12/12/2025',
					'Y-m-d'  => '2025-12-12',
				),
				'default'     => self::get_default_setting( $defaults, 'reviewDateFormat' ),
				'render_type' => 'template',
			)
		);

		$this->add_control(
			'starRatingSize',
			array(
				'label'       => __( 'Star Rating Size', 'ugcify' ),
				'type'        => Controls_Manager::SELECT,
				'options'     => array(
					'small'  => __( 'Small', 'ugcify' ),
					'medium' => __( 'Medium', 'ugcify' ),
					'large'  => __( 'Large', 'ugcify' ),
				),
				'default'     => self::get_default_setting( $defaults, 'starRatingSize' ),
				'render_type' => 'template',
			)
		);

		$this->add_control(
			'reviewTextSize',
			array(
				'label'       => __( 'Review Text Size', 'ugcify' ),
				'type'        => Controls_Manager::SELECT,
				'options'     => array(
					'small'  => __( 'Small', 'ugcify' ),
					'medium' => __( 'Medium', 'ugcify' ),
					'large'  => __( 'Large', 'ugcify' ),
				),
				'default'     => self::get_default_setting( $defaults, 'reviewTextSize' ),
				'render_type' => 'template',
			)
		);

		$this->add_control(
			'reviewTextLength',
			array(
				'label'       => __( 'Review Text Length', 'ugcify' ),
				'type'        => Controls_Manager::SELECT,
				'options'     => array(
					'small'  => __( 'Small', 'ugcify' ),
					'medium' => __( 'Medium', 'ugcify' ),
					'large'  => __( 'Large', 'ugcify' ),
					'full'   => __( 'Full', 'ugcify' ),
				),
				'default'     => self::get_default_setting( $defaults, 'reviewTextLength' ),
				'render_type' => 'template',
			)
		);

		$this->add_control(
			'reviewCardBorderRadius',
			array(
				'label'       => __( 'Review Card Border Radius', 'ugcify' ),
				'type'        => Controls_Manager::NUMBER,
				'min'         => 0,
				'max'         => 100,
				'step'        => 1,
				'default'     => absint( self::get_default_setting( $defaults, 'reviewCardBorderRadius' ) ),
				'render_type' => 'template',
				'condition'   => array(
					'blockTemplate' => array( 'minimal_gallery', 'reels', 'media_mosaic' ),
				),
			)
		);

		$this->add_control(
			'reviewColumn',
			array(
				'label'       => __( 'Review Columns', 'ugcify' ),
				'type'        => Controls_Manager::SELECT,
				'options'     => array(
					'1' => '1',
					'2' => '2',
					'3' => '3',
					'4' => '4',
				),
				'default'     => self::get_default_setting( $defaults, 'reviewColumn' ),
				'render_type' => 'template',
				'condition'   => array(
					'blockTemplate' => array( 'minimal_gallery', 'reels' ),
				),
			)
		);

		$this->add_control(
			'reviewsPerPage',
			array(
				'label'       => __( 'Reviews Per Page', 'ugcify' ),
				'type'        => Controls_Manager::NUMBER,
				'min'         => 1,
				'max'         => 50,
				'step'        => 1,
				'default'     => absint( self::get_default_setting( $defaults, 'reviewsPerPage' ) ),
				'render_type' => 'template',
			)
		);

		$this->add_control(
			'showReviews',
			array(
				'label'       => __( 'Show Reviews', 'ugcify' ),
				'type'        => Controls_Manager::SWITCHER,
				'default'     => self::get_default_setting( $defaults, 'showReviews' ) ? 'yes' : '',
				'render_type' => 'template',
				'condition'   => array(
					'blockTemplate' => $gallery_templates,
				),
			)
		);
		$this->add_control(
			'showLoadMoreButton',
			array(
				'label'       => __( 'Show Load More Button', 'ugcify' ),
				'type'        => Controls_Manager::SWITCHER,
				'default'     => self::get_default_setting( $defaults, 'showLoadMoreButton' ) ? 'yes' : '',
				'render_type' => 'template',
				'condition'   => array(
					'blockTemplate' => $gallery_templates,
				),
			)
		);
		$this->add_control(
			'loadMoreTextSize',
			array(
				'label'       => __( 'Load More Text Size', 'ugcify' ),
				'type'        => Controls_Manager::SELECT,
				'options'     => array(
					'small'  => __( 'Small', 'ugcify' ),
					'medium' => __( 'Medium', 'ugcify' ),
					'large'  => __( 'Large', 'ugcify' ),
				),
				'default'     => self::get_default_setting( $defaults, 'loadMoreTextSize' ),
				'render_type' => 'template',
				'condition'   => array(
					'blockTemplate' => $gallery_templates,
				),
			)
		);
		$this->add_control(
			'loadMoreBorderRadius',
			array(
				'label'       => __( 'Load More Border Radius', 'ugcify' ),
				'type'        => Controls_Manager::NUMBER,
				'min'         => 0,
				'max'         => 100,
				'step'        => 1,
				'default'     => absint( self::get_default_setting( $defaults, 'loadMoreBorderRadius' ) ),
				'render_type' => 'template',
				'condition'   => array(
					'blockTemplate' => $gallery_templates,
				),
			)
		);

		$this->end_controls_section();
	}

	/**
	 * Register action controls.
	 *
	 * @return void
	 */
	private function register_action_controls() {
		$this->start_controls_section(
			'ugcify_actions',
			array(
				'label' => __( 'Actions', 'ugcify' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);

		$this->add_control(
			'reset_to_defaults',
			array(
				'type'        => Controls_Manager::BUTTON,
				'text'        => __( 'Reset to defaults', 'ugcify' ),
				'button_type' => 'default',
				'event'       => 'ugcCommerceElementor:resetDefaults',
			)
		);

		$this->end_controls_section();
	}

	/**
	 * Render widget.
	 *
	 * @return void
	 */
	protected function render() {
		if ( ! shortcode_exists( 'ugcify_reviews' ) ) {
			return;
		}

		$settings = $this->get_settings_for_display();
		$settings = $this->normalize_settings_for_plan( is_array( $settings ) ? $settings : array() );

		$product_id = isset( $settings['productId'] ) ? absint( $settings['productId'] ) : 0;
		$categories = $this->sanitize_slug_array( isset( $settings['categories'] ) ? $settings['categories'] : array() );
		$tags       = $this->sanitize_slug_array( isset( $settings['tags'] ) ? $settings['tags'] : array() );

		$instance_id = 'ugcify-el-' . sanitize_html_class( (string) $this->get_id() );
		if ( '' === $instance_id ) {
			$instance_id = 'ugcify-el-' . wp_unique_id();
		}

		$shortcode_attributes = array(
			'instance_id' => $instance_id,
		);

		if ( $product_id > 0 ) {
			$shortcode_attributes['product_id'] = (string) $product_id;
		}

		if ( ! empty( $categories ) ) {
			$shortcode_attributes['categories'] = implode( ',', $categories );
		}

		if ( ! empty( $tags ) ) {
			$shortcode_attributes['tags'] = implode( ',', $tags );
		}

		foreach ( self::get_template_control_keys() as $key ) {
			if ( ! isset( $settings[ $key ] ) ) {
				continue;
			}

			$sanitized_value = $this->sanitize_template_setting_value( $key, $settings[ $key ] );

			if ( is_bool( $sanitized_value ) ) {
				$shortcode_attributes[ $key ] = $sanitized_value ? '1' : '0';
			} else {
				$shortcode_attributes[ $key ] = (string) $sanitized_value;
			}
		}

		if ( 'media_mosaic' === $settings['widgetType'] ) {
			$media_mosaic_style = $this->sanitize_template_setting_value(
				'mediaMosaicStyle',
				isset( $settings['mediaMosaicStyle'] ) ? $settings['mediaMosaicStyle'] : 'grid'
			);
			$shortcode_attributes['media_mosaic_style'] = (string) $media_mosaic_style;
		}

		$shortcode = '[ugcify_reviews';
		foreach ( $shortcode_attributes as $key => $value ) {
			$shortcode .= sprintf(
				' %1$s="%2$s"',
				sanitize_key( $key ),
				esc_attr( $value )
			);
		}
		$shortcode .= ']';

		$output = do_shortcode( $shortcode );

		$this->enqueue_elementor_runtime_assets();

		if ( $this->is_elementor_editor_preview() ) {
			$output = $this->wrap_editor_preview_output( $output );
		} else {
			$output = $this->get_runtime_style_links() . $output;
		}

		echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
	}

	/**
	 * Return template-setting keys only.
	 *
	 * @return array
	 */
	private static function get_template_control_keys() {
		$defaults = self::get_default_settings();
		unset( $defaults['productId'], $defaults['categories'], $defaults['tags'], $defaults['minimalWidgetType'] );
		return array_keys( $defaults );
	}

	/**
	 * Sanitize template setting value.
	 *
	 * @param string $key   Setting key.
	 * @param mixed  $value Setting value.
	 * @return mixed
	 */
	private function sanitize_template_setting_value( $key, $value ) {
		$defaults = self::get_default_settings();
		$default  = isset( $defaults[ $key ] ) ? $defaults[ $key ] : '';

		$size_values = array( 'small', 'medium', 'large' );

		switch ( $key ) {
			case 'widgetType':
			case 'minimalWidgetType':
				return in_array( $value, array( 'grid', 'masonry', 'slider', 'reels', 'gallery', 'card_carousel', 'media_mosaic', 'testimonial_carousel' ), true ) ? $value : $default;

			case 'blockTemplate':
				return in_array( $value, array( 'minimal_gallery', 'reels', 'carousel', 'card_carousel', 'media_mosaic', 'testimonial_carousel' ), true ) ? $value : $default;

			case 'titleFontWeight':
				return in_array( $value, array( '400', '500', '600', '700' ), true ) ? $value : $default;

			case 'titleFontSize':
			case 'reviewerNameFontSize':
			case 'starRatingSize':
			case 'reviewTextSize':
			case 'testimonialQuoteSize':
				return in_array( $value, $size_values, true ) ? $value : $default;

			case 'reviewerNameFormat':
				return in_array(
					$value,
					array( 'full', 'first_last_initial', 'first_only', 'initials' ),
					true
				) ? $value : $default;

			case 'reviewDateFormat':
				return in_array( $value, array( 'd M, Y', 'M d, Y', 'd/m/Y', 'Y-m-d' ), true ) ? $value : $default;

			case 'reviewTextLength':
				return in_array( $value, array( 'small', 'medium', 'large', 'full' ), true ) ? $value : $default;

			case 'reviewColumn':
				return in_array( (string) $value, array( '1', '2', '3', '4' ), true ) ? (string) $value : $default;

			case 'reviewsPerPage':
				$reviews_per_page = absint( $value );
				if ( $reviews_per_page < 1 ) {
					return (string) $default;
				}
				return (string) min( 50, $reviews_per_page );

			case 'reviewCardBorderRadius':
			case 'loadMoreBorderRadius':
				return (string) min( 100, absint( $value ) );

			case 'gridStyle':
				return in_array( $value, array( 'masonry', 'uniform_grid' ), true ) ? $value : $default;

			case 'mediaMosaicStyle':
				return in_array( $value, array( 'grid', 'masonry', 'slider' ), true ) ? $value : $default;

			case 'tagStyle':
				return in_array( $value, array( 'pulsing_dot', 'simple_badge', 'none' ), true ) ? $value : $default;

			case 'showHeaderTitle':
			case 'showCustomerAvatar':
			case 'showVerifiedCheck':
			case 'showInfluencerBadge':
			case 'showReviews':
			case 'showLoadMoreButton':
			case 'lazyLoadImages':
			case 'autoplayVideo':
			case 'enableLightbox':
			case 'showMediaCarousel':
			case 'showStories':
			case 'showAddYours':
			case 'showCommunity':
			case 'showShareBtn':
			case 'directAddToCart':
				$bool_value = filter_var( $value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE );
				return null === $bool_value ? (bool) $default : $bool_value;

			case 'columnsDesktop':
				return (string) min( 6, max( 1, absint( $value ) ) );

			case 'gapSpacing':
				return (string) min( 60, max( 0, absint( $value ) ) );

			case 'mediaCarouselItemsToShow':
				return (string) min( 100, max( 1, absint( $value ) ) );

			case 'testimonialQuoteOpacity':
				if ( is_array( $value ) && isset( $value['size'] ) ) {
					$value = (float) $value['size'] / 100;
				}
				return (string) min( 1, max( 0, (float) $value ) );

			case 'storiesMaxCount':
				return (string) min( 20, max( 1, absint( $value ) ) );

			case 'loadMoreTextSize':
				return in_array( $value, $size_values, true ) ? $value : $default;

			case 'primaryColor':
			case 'titleColor':
			case 'bodyFontColor':
			case 'cardBgColor':
			case 'ratingColor':
			case 'buttonTextColor':
			case 'filterFillColor':
			case 'filterStrokeColor':
			case 'filterIconColor':
			case 'readMoreColor':
			case 'loadMoreTextColor':
			case 'loadMoreBgColor':
			case 'loadMoreBorderColor':
			case 'testimonialQuoteColor':
				$sanitized_color = sanitize_hex_color( (string) $value );
				return $sanitized_color ? $sanitized_color : $default;

			default:
				return sanitize_text_field( (string) $value );
		}
	}

	/**
	 * Sanitize slug array.
	 *
	 * @param mixed $raw_values Raw values.
	 * @return array
	 */
	private function sanitize_slug_array( $raw_values ) {
		if ( ! is_array( $raw_values ) ) {
			return array();
		}

		$values = array_map( 'sanitize_title', $raw_values );
		$values = array_filter( $values );
		$values = array_values( array_unique( $values ) );

		return $values;
	}

	/**
	 * Get block-data endpoint URL.
	 *
	 * @param string $path Endpoint path.
	 * @param array  $args Query args.
	 * @return string
	 */
	private function get_block_data_url( $path, $args = array() ) {
		$base_url = rest_url( 'ugcify/v1/' . ltrim( $path, '/' ) );
		$args     = is_array( $args ) ? $args : array();
		$args['_wpnonce'] = wp_create_nonce( 'wp_rest' );

		return add_query_arg( $args, $base_url );
	}

	/**
	 * Get initial product options for select control.
	 *
	 * @return array
	 */
	private function get_product_options_for_control() {
		$options = array();

		if ( ! function_exists( 'wc_get_products' ) || ! function_exists( 'wc_get_product' ) ) {
			return $options;
		}

		$products = wc_get_products(
			array(
				'status' => array( 'publish' ),
				'limit'  => 20,
				'return' => 'objects',
			)
		);

		foreach ( $products as $product ) {
			if ( ! $product ) {
				continue;
			}
			$options[ (string) $product->get_id() ] = (string) $product->get_name();
		}

		return $options;
	}

	/**
	 * Get initial term options for select controls.
	 *
	 * @param string $taxonomy Taxonomy.
	 * @return array
	 */
	private function get_term_options_for_control( $taxonomy ) {
		$options = array();

		if ( ! taxonomy_exists( $taxonomy ) ) {
			return $options;
		}

		$terms = get_terms(
			array(
				'taxonomy'   => $taxonomy,
				'hide_empty' => false,
				'number'     => 20,
				'orderby'    => 'name',
				'order'      => 'ASC',
			)
		);

		if ( is_array( $terms ) && ! is_wp_error( $terms ) ) {
			foreach ( $terms as $term ) {
				$options[ (string) $term->slug ] = (string) $term->name;
			}
		}

		return $options;
	}

	/**
	 * Determine if Elementor editor preview is active.
	 *
	 * @return bool
	 */
	private function is_elementor_editor_preview() {
		if ( ! class_exists( '\Elementor\Plugin' ) ) {
			return false;
		}

		return \Elementor\Plugin::$instance->editor->is_edit_mode();
	}

	/**
	 * Wrap output for non-interactive editor preview.
	 *
	 * @param string $output Shortcode output.
	 * @return string
	 */
	private function wrap_editor_preview_output( $output ) {
		static $style_output = '';

		if ( '' === $style_output ) {
			$css_file = UGCIFY_PATH . 'assets/frontend/styles.css';
			$base_css = '';
			if ( file_exists( $css_file ) && is_readable( $css_file ) ) {
				$raw_css = file_get_contents( $css_file );
				if ( is_string( $raw_css ) ) {
					$base_css = $raw_css;
				}
			}

			$preview_css = '.elementor-editor-active .ugcify-elementor-preview-lock a,'
				. '.elementor-editor-active .ugcify-elementor-preview-lock button,'
				. '.elementor-editor-active .ugcify-elementor-preview-lock input,'
				. '.elementor-editor-active .ugcify-elementor-preview-lock select,'
				. '.elementor-editor-active .ugcify-elementor-preview-lock textarea,'
				. '.elementor-editor-active .ugcify-elementor-preview-lock .page-numbers{'
				. 'pointer-events:none !important;cursor:default !important;}';

			$style_output = '<style class="ugcify-elementor-preview-styles">' . $base_css . $preview_css . '</style>';
		}

		return $style_output . '<div class="ugcify-elementor-preview-lock">' . $output . '</div>';
	}

	/**
	 * Normalize widget settings for current plan and selected template.
	 *
	 * @param array $settings Raw settings.
	 * @return array
	 */
	private function normalize_settings_for_plan( $settings ) {
		$defaults = self::get_default_settings();
		$has_minimal_widget_type = isset( $settings['minimalWidgetType'] ) && '' !== $settings['minimalWidgetType'];
		$settings = array_merge( $defaults, $settings );

		$block_template = $this->sanitize_template_setting_value( 'blockTemplate', $settings['blockTemplate'] );
		$legacy_widget_type = $this->sanitize_template_setting_value( 'widgetType', $settings['widgetType'] );
		$minimal_widget_type = $has_minimal_widget_type ? $this->sanitize_template_setting_value( 'minimalWidgetType', $settings['minimalWidgetType'] ) : $legacy_widget_type;
		$gallery_templates = array( 'carousel', 'card_carousel', 'media_mosaic', 'testimonial_carousel' );

		if ( empty( $settings['blockTemplate'] ) || ! in_array( $block_template, array_merge( array( 'minimal_gallery', 'reels' ), $gallery_templates ), true ) ) {
			if ( 'reels' === $legacy_widget_type ) {
				$block_template = 'reels';
			} elseif ( 'gallery' === $legacy_widget_type ) {
				$block_template = 'carousel';
			} elseif ( in_array( $legacy_widget_type, array( 'card_carousel', 'media_mosaic', 'testimonial_carousel' ), true ) ) {
				$block_template = $legacy_widget_type;
			} else {
				$block_template = 'minimal_gallery';
			}
		}

		if ( 'reels' === $block_template && ! FeatureGate::is_enabled( 'block_studio_reels' ) ) {
			$block_template = 'minimal_gallery';
		}
		if ( in_array( $block_template, $gallery_templates, true ) && ! FeatureGate::is_enabled( 'block_studio_gallery' ) ) {
			$block_template = 'minimal_gallery';
		}

		$settings['blockTemplate'] = $block_template;
		if ( 'reels' === $block_template ) {
			$settings['widgetType'] = 'reels';
		} elseif ( 'carousel' === $block_template ) {
			$settings['widgetType'] = 'gallery';
		} elseif ( in_array( $block_template, array( 'card_carousel', 'media_mosaic', 'testimonial_carousel' ), true ) ) {
			$settings['widgetType'] = $block_template;
		} else {
			$settings['widgetType'] = in_array( $minimal_widget_type, array( 'grid', 'masonry', 'slider' ), true ) ? $minimal_widget_type : 'grid';
		}

		if ( ! FeatureGate::is_enabled( 'block_studio_advanced' ) ) {
			foreach ( array(
				'primaryColor',
				'titleColor',
				'bodyFontColor',
				'cardBgColor',
				'ratingColor',
				'buttonTextColor',
				'filterFillColor',
				'filterStrokeColor',
				'filterIconColor',
				'readMoreColor',
				'loadMoreTextColor',
				'loadMoreBgColor',
				'loadMoreBorderColor',
				'lazyLoadImages',
				'autoplayVideo',
				'enableLightbox',
			) as $locked_key ) {
				$settings[ $locked_key ] = self::get_default_setting( $defaults, $locked_key );
			}
		}

		foreach ( array( 'enableUpvotes', 'socialShareButtons', 'customersAlsoBought' ) as $locked_key ) {
			$settings[ $locked_key ] = self::get_default_setting( $defaults, $locked_key );
		}

		return $settings;
	}

	/**
	 * Ensure frontend assets are available in Elementor output.
	 *
	 * @return void
	 */
	private function enqueue_elementor_runtime_assets() {
		static $done = false;
		if ( $done ) {
			return;
		}

		$done = true;
		if ( wp_script_is( 'ugcify-frontend', 'enqueued' ) && wp_style_is( 'ugcify-frontend', 'enqueued' ) ) {
			return;
		}

		$script_file       = UGCIFY_PATH . 'assets/frontend/app.js';
		$script_asset_file = UGCIFY_PATH . 'assets/frontend/app.asset.php';
		$script_asset      = array(
			'dependencies' => array( 'jquery', 'wp-i18n' ),
			'version'      => file_exists( $script_file ) ? (string) filemtime( $script_file ) : UGCIFY_VERSION,
		);
		if ( file_exists( $script_asset_file ) ) {
			$loaded_asset = require $script_asset_file;
			if ( is_array( $loaded_asset ) ) {
				$script_asset = array_merge( $script_asset, $loaded_asset );
			}
		}
		$script_asset['dependencies'] = array_values(
			array_unique(
				array_merge(
					array( 'jquery', 'wp-i18n' ),
					isset( $script_asset['dependencies'] ) && is_array( $script_asset['dependencies'] ) ? $script_asset['dependencies'] : array()
				)
			)
		);

		$style_file       = UGCIFY_PATH . 'assets/frontend/styles.css';
		$style_asset_file = UGCIFY_PATH . 'assets/frontend/styles.asset.php';
		$style_asset      = array(
			'version' => file_exists( $style_file ) ? (string) filemtime( $style_file ) : UGCIFY_VERSION,
		);
		if ( file_exists( $style_asset_file ) ) {
			$loaded_asset = require $style_asset_file;
			if ( is_array( $loaded_asset ) ) {
				$style_asset = array_merge( $style_asset, $loaded_asset );
			}
		}
		if ( file_exists( $style_file ) ) {
			$style_asset['version'] = (string) filemtime( $style_file );
		}

		wp_enqueue_script( 'ugcify-frontend', UGCIFY_URL . 'assets/frontend/app.js', $script_asset['dependencies'], $script_asset['version'], true );
		wp_enqueue_style( 'ugcify-frontend', UGCIFY_URL . 'assets/frontend/styles.css', array(), $style_asset['version'] );
		wp_set_script_translations( 'ugcify-frontend', 'ugcify', UGCIFY_PATH . 'languages' );

		wp_localize_script(
			'ugcify-frontend',
			'ugcCommerce',
			array(
				'apiUrl'           => rest_url( 'ugcify/v1' ),
				'ajaxUrl'          => admin_url( 'admin-ajax.php' ),
				'nonce'            => wp_create_nonce( 'wp_rest' ),
				'pluginUrl'        => UGCIFY_URL,
				'productId'        => 0,
				'perPage'          => apply_filters( 'ugcify_reviews_per_page', 3 ),
				'locale'           => str_replace( '_', '-', get_locale() ),
				'gmtOffset'        => (float) get_option( 'gmt_offset', 0 ),
				'wcCartRedirect'   => 'yes' === get_option( 'woocommerce_cart_redirect_after_add', 'no' ),
				'wcCartUrl'        => function_exists( 'wc_get_cart_url' ) ? wc_get_cart_url() : '',
				'isLoggedIn'       => is_user_logged_in(),
				'rewardsEnabled'   => \Ugcify\Admin\API\RewardSettingsAPI::is_enabled(),
				'socialShareEnabled' => \Ugcify\Admin\API\RewardSettingsAPI::is_social_share_enabled(),
				'isProActive'      => (bool) apply_filters( 'ugcify_is_pro_active', false ),
				'licensePlan'      => (string) apply_filters( 'ugcify_license_plan', '' ),
				'features'         => array(
					'block_studio_advanced' => FeatureGate::is_enabled( 'block_studio_advanced' ),
					'block_studio_reels'    => FeatureGate::is_enabled( 'block_studio_reels' ),
					'block_studio_gallery'  => FeatureGate::is_enabled( 'block_studio_gallery' ),
				),
				'upgradeUrl'       => esc_url( apply_filters( 'ugcify_upgrade_url', admin_url( 'admin.php?page=ugcify#/license' ) ) ),
				'i18n'             => array(
					'guest'                => __( 'Guest', 'ugcify' ),
					'reviewMediaAlt'       => __( 'Review Media', 'ugcify' ),
					'errorLoadingReview'   => __( 'Failed to load review.', 'ugcify' ),
					'failedFetchReview'    => __( 'Failed to fetch review', 'ugcify' ),
					'failedFetchReviewIds' => __( 'Failed to fetch review ids', 'ugcify' ),
					'addingToCart'         => __( 'Adding...', 'ugcify' ),
					'addedToCart'          => __( 'Added', 'ugcify' ),
					'addToCartError'       => __( 'Try Again', 'ugcify' ),
					'readMore'             => __( 'Read More', 'ugcify' ),
					'readLess'             => __( 'Read less', 'ugcify' ),
					'shareDefaultText'     => __( 'Check out this review:', 'ugcify' ),
					'helpful'              => __( 'Helpful', 'ugcify' ),
					'notHelpful'           => __( 'Not helpful', 'ugcify' ),
					'loginToVote'          => __( 'Log in to vote on this review.', 'ugcify' ),
					'voteError'            => __( 'Could not save your vote. Please try again.', 'ugcify' ),
					'shareCopiedLabel'     => __( 'Copied!', 'ugcify' ),
					'shareCopyManualLabel' => __( 'Press Ctrl+C to copy', 'ugcify' ),
					'shareErrorLabel'      => __( 'Could not create share link. Please try again.', 'ugcify' ),
				),
			)
		);
	}

	/**
	 * Return stylesheet fallbacks when Elementor renders after wp_head.
	 *
	 * @return string
	 */
	private function get_runtime_style_links() {
		static $printed = false;
		if ( $printed || wp_style_is( 'ugcify-frontend', 'done' ) ) {
			return '';
		}

		$printed = true;
		$style_file = UGCIFY_PATH . 'assets/frontend/styles.css';
		return sprintf(
			'<link rel="stylesheet" id="ugcify-elementor-runtime-css" href="%1$s" media="all" />',
			esc_url( UGCIFY_URL . 'assets/frontend/styles.css?ver=' . rawurlencode( file_exists( $style_file ) ? (string) filemtime( $style_file ) : UGCIFY_VERSION ) )
		);
	}
}
