<?php
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals -- Template/class file; variables are widget-scoped, not true globals.

/**
 * New single-product Elementor widgets for Storzen v1.2.
 *
 * Adds three previously-missing widgets to the "Product Details" panel category:
 *
 *  • Storzen_Product_Reviews_Widget   — standalone WooCommerce reviews section
 *  • Storzen_Product_Stock_Widget     — real stock status + optional progress bar
 *  • Storzen_Product_Upsells_Widget   — upsell products (grid or carousel layout)
 *
 * INSTALLATION:
 *   1. Copy this file into:
 *        storzen/elementor/widgets/class-storzen-style-product-single-parts-new.php
 *   2. Apply the patch to storzen-elementor-widgets-init.php (see patch file).
 *   3. Apply the patch to inc/admin-panel.php (see patch file).
 *   4. Apply the patch to inc/class-storzen-init.php (see patch file).
 *
 * All three widgets use the existing Storzen_Product_Part_Helpers trait
 * (defined in class-storzen-style-product-single-parts.php) for DRY
 * placeholder / product-getter / wrapper helpers. That file is always
 * require_once'd before this one, so the trait is guaranteed to exist.
 *
 * @package storzen
 * @since   1.2.0
 */

namespace Elementor;

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

// ─────────────────────────────────────────────────────────────────────────────
// Widget 1: Product Reviews
// ─────────────────────────────────────────────────────────────────────────────

/**
 * Standalone WooCommerce product reviews section.
 *
 * Renders the full reviews block (rating summary + comment list + review form)
 * at any position chosen in the page builder, independently of the Product
 * Tabs widget. Built on the native WooCommerce comments_template() call so it
 * inherits all WooCommerce review-form hooks and theme overrides.
 *
 * Toggle key:  product_reviews
 * Category:    storzen-product-details
 *
 * @since 1.2.0
 */
class Storzen_Product_Reviews_Widget extends Widget_Base {

	use Storzen_Product_Part_Helpers;

	// ── Identity ──────────────────────────────────────────────────────────────

	public function get_name() {
		return 'storzen-product-reviews';
	}

	public function get_title() {
		return esc_html__( 'Product Reviews', 'storzen' );
	}

	public function get_icon() {
		return 'eicon-review';
	}

	public function get_categories() {
		return array( 'storzen-product-details' );
	}

	public function get_keywords() {
		return array( 'reviews', 'comments', 'ratings', 'testimonials', 'product', 'storzen' );
	}

	// ── Controls ──────────────────────────────────────────────────────────────

	protected function register_controls() {

		// ── Content tab ───────────────────────────────────────────────────────

		$this->start_controls_section(
			'section_reviews_content',
			array(
				'label' => esc_html__( 'Reviews', 'storzen' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);

		$this->add_control(
			'section_title',
			array(
				'label'       => esc_html__( 'Section Title', 'storzen' ),
				'type'        => Controls_Manager::TEXT,
				'default'     => esc_html__( 'Customer Reviews', 'storzen' ),
				'placeholder' => esc_html__( 'Customer Reviews', 'storzen' ),
				'description' => esc_html__( 'Leave empty to hide the title.', 'storzen' ),
			)
		);

		$this->add_control(
			'title_tag',
			array(
				'label'   => esc_html__( 'Title HTML Tag', 'storzen' ),
				'type'    => Controls_Manager::SELECT,
				'default' => 'h2',
				'options' => array(
					'h2' => 'H2',
					'h3' => 'H3',
					'h4' => 'H4',
					'h5' => 'H5',
					'h6' => 'H6',
				),
			)
		);

		$this->add_control(
			'show_rating_summary',
			array(
				'label'        => esc_html__( 'Show Rating Summary Bar', 'storzen' ),
				'type'         => Controls_Manager::SWITCHER,
				'label_on'     => esc_html__( 'Show', 'storzen' ),
				'label_off'    => esc_html__( 'Hide', 'storzen' ),
				'return_value' => 'yes',
				'default'      => 'yes',
				'description'  => esc_html__( 'Shows average score + per-star breakdown. Hidden when the product has no reviews.', 'storzen' ),
			)
		);

		$this->add_control(
			'show_review_form',
			array(
				'label'        => esc_html__( 'Show Review Form', 'storzen' ),
				'type'         => Controls_Manager::SWITCHER,
				'label_on'     => esc_html__( 'Show', 'storzen' ),
				'label_off'    => esc_html__( 'Hide', 'storzen' ),
				'return_value' => 'yes',
				'default'      => 'yes',
			)
		);

		$this->add_control(
			'reviews_per_page',
			array(
				'label'       => esc_html__( 'Reviews Per Page', 'storzen' ),
				'type'        => Controls_Manager::NUMBER,
				'min'         => 1,
				'max'         => 50,
				'step'        => 1,
				'default'     => 5,
				'description' => esc_html__( 'Controls how many reviews are shown before pagination.', 'storzen' ),
			)
		);

		$this->end_controls_section();

		// ── Style tab ─────────────────────────────────────────────────────────

		$this->start_controls_section(
			'section_reviews_style_title',
			array(
				'label' => esc_html__( 'Section Title', 'storzen' ),
				'tab'   => Controls_Manager::TAB_STYLE,
			)
		);

		$this->add_control(
			'title_color',
			array(
				'label'     => esc_html__( 'Color', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'selectors' => array(
					'{{WRAPPER}} .sz-reviews-section-title' => 'color: {{VALUE}};',
				),
			)
		);

		$this->add_group_control(
			Group_Control_Typography::get_type(),
			array(
				'name'     => 'title_typography',
				'selector' => '{{WRAPPER}} .sz-reviews-section-title',
			)
		);

		$this->add_responsive_control(
			'title_margin_bottom',
			array(
				'label'      => esc_html__( 'Margin Bottom', 'storzen' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px', 'em', 'rem' ),
				'range'      => array(
					'px' => array( 'min' => 0, 'max' => 80 ),
				),
				'default'    => array( 'unit' => 'px', 'size' => 20 ),
				'selectors'  => array(
					'{{WRAPPER}} .sz-reviews-section-title' => 'margin-bottom: {{SIZE}}{{UNIT}};',
				),
			)
		);

		$this->end_controls_section();

		$this->start_controls_section(
			'section_reviews_style_summary',
			array(
				'label'     => esc_html__( 'Rating Summary', 'storzen' ),
				'tab'       => Controls_Manager::TAB_STYLE,
				'condition' => array( 'show_rating_summary' => 'yes' ),
			)
		);

		$this->add_control(
			'star_color',
			array(
				'label'     => esc_html__( 'Star Color', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '#f0c040',
				'selectors' => array(
					'{{WRAPPER}} .sz-rating-summary .star-rating span' => 'color: {{VALUE}};',
					'{{WRAPPER}} .sz-rating-bars .sz-bar-star'         => 'color: {{VALUE}};',
				),
			)
		);

		$this->add_control(
			'bar_fill_color',
			array(
				'label'     => esc_html__( 'Bar Fill Color', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '#f0c040',
				'selectors' => array(
					'{{WRAPPER}} .sz-bar-fill' => 'background-color: {{VALUE}};',
				),
			)
		);

		$this->end_controls_section();
	}

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

	protected function render() {

		if ( $this->szp_maybe_placeholder( esc_html__( 'Product Reviews — visible on a single product page.', 'storzen' ) ) ) {
			return;
		}

		$product = $this->szp_get_loop_product();
		if ( ! $product ) {
			return;
		}

		// Reviews must be enabled in WooCommerce settings.
		if ( ! post_type_supports( 'product', 'comments' ) ) {
			return;
		}

		$settings = $this->get_settings_for_display();

		echo '<div class="sz-product-reviews-widget">';

		// ── Optional section title ─────────────────────────────────────────
		$title = isset( $settings['section_title'] ) ? trim( (string) $settings['section_title'] ) : '';
		if ( $title !== '' ) {
			$tag = isset( $settings['title_tag'] ) ? sanitize_key( $settings['title_tag'] ) : 'h2';
			if ( ! in_array( $tag, array( 'h2', 'h3', 'h4', 'h5', 'h6' ), true ) ) {
				$tag = 'h2';
			}
			printf(
				'<%1$s class="sz-reviews-section-title">%2$s</%1$s>',
				esc_attr( $tag ),
				esc_html( $title )
			);
		}

		// ── Rating summary ────────────────────────────────────────────────
		if ( 'yes' === ( $settings['show_rating_summary'] ?? 'yes' ) && $product->get_review_count() > 0 ) {
			$this->render_rating_summary( $product );
		}

		// ── WooCommerce reviews (comment list + form) ─────────────────────
		// Filter: reviews per page.
		$reviews_per_page = max( 1, (int) ( $settings['reviews_per_page'] ?? 5 ) );
		add_filter(
			'option_comments_per_page',
			static function() use ( $reviews_per_page ) {
				return $reviews_per_page;
			}
		);

		// Filter: hide review form if the toggle is off.
		$show_form        = 'yes' === ( $settings['show_review_form'] ?? 'yes' );
		$hide_form_filter = null;
		if ( ! $show_form ) {
			$hide_form_filter = static function ( $open ) {
				return false;
			};
			add_filter( 'comments_open', $hide_form_filter );
		}

		// Set $product global required by woocommerce/templates/single-product-reviews.php.
		$this->szp_setup_global_product();

		comments_template();

		// Clean up our temporary filters so they don't affect anything else.
		remove_all_filters( 'option_comments_per_page' );
		if ( $hide_form_filter ) {
			remove_filter( 'comments_open', $hide_form_filter );
		}

		echo '</div><!-- .sz-product-reviews-widget -->';
	}

	// ── Rating summary helper ─────────────────────────────────────────────────

	/**
	 * Render the star-breakdown summary above the review list.
	 *
	 * @param \WC_Product $product
	 */
	private function render_rating_summary( \WC_Product $product ) {

		$avg    = (float) $product->get_average_rating();
		$count  = (int) $product->get_review_count();
		$counts = $product->get_rating_counts(); // array: [ 5 => N, 4 => N, … ]

		echo '<div class="sz-rating-summary">';

		// Left: big average score + overall stars + review count.
		echo '<div class="sz-rating-summary__score">';
		echo '<span class="sz-avg-score">' . esc_html( number_format( $avg, 1 ) ) . '</span>';
		echo '<div class="sz-avg-stars">';
		echo wp_kses_post( wc_get_rating_html( $avg, $count ) );
		echo '</div>';
		printf(
			'<span class="sz-review-count">%s</span>',
			esc_html(
				sprintf(
					/* translators: %d: number of reviews */
					_n( '%d review', '%d reviews', $count, 'storzen' ),
					$count
				)
			)
		);
		echo '</div><!-- .sz-rating-summary__score -->';

		// Right: per-star breakdown bars (5 → 1).
		echo '<div class="sz-rating-bars">';
		for ( $star = 5; $star >= 1; $star-- ) {
			$star_count = isset( $counts[ $star ] ) ? (int) $counts[ $star ] : 0;
			$pct        = $count > 0 ? round( ( $star_count / $count ) * 100 ) : 0;
			printf(
				'<div class="sz-rating-bar-row">
					<span class="sz-bar-star">%1$d ★</span>
					<div class="sz-bar-track" role="progressbar" aria-valuenow="%2$d" aria-valuemin="0" aria-valuemax="100" aria-label="%3$s">
						<div class="sz-bar-fill" style="width:%2$d%%"></div>
					</div>
					<span class="sz-bar-count">%4$d</span>
				</div>',
				absint( $star ),
				absint( $pct ),
				/* translators: 1: star number, 2: percentage */
				esc_attr( sprintf( __( '%1$d-star reviews: %2$d%%', 'storzen' ), $star, $pct ) ),
				absint( $star_count )
			);
		}
		echo '</div><!-- .sz-rating-bars -->';

		echo '</div><!-- .sz-rating-summary -->';
	}
}


// ─────────────────────────────────────────────────────────────────────────────
// Widget 2: Product Stock
// ─────────────────────────────────────────────────────────────────────────────

/**
 * Real-time WooCommerce stock status display widget.
 *
 * Shows "In Stock", "Only N left!", or "Out of Stock" messages sourced
 * directly from WooCommerce stock management (managing_stock + get_stock_quantity).
 * Optionally renders a visual progress bar to reinforce scarcity urgency.
 *
 * Complements the Stock Scarcity MODULE (which appends to the price area via
 * storzen_product_single_after_price hook). This is a standalone positional
 * WIDGET that a builder can place anywhere on the product template.
 *
 * Toggle key:  product_stock_widget
 * Category:    storzen-product-details
 *
 * @since 1.2.0
 */
class Storzen_Product_Stock_Widget extends Widget_Base {

	use Storzen_Product_Part_Helpers;

	// ── Identity ──────────────────────────────────────────────────────────────

	public function get_name() {
		return 'storzen-product-stock';
	}

	public function get_title() {
		return esc_html__( 'Product Stock', 'storzen' );
	}

	public function get_icon() {
		return 'eicon-counter';
	}

	public function get_categories() {
		return array( 'storzen-product-details' );
	}

	public function get_keywords() {
		return array( 'stock', 'inventory', 'scarcity', 'urgency', 'availability', 'storzen' );
	}

	// ── Controls ──────────────────────────────────────────────────────────────

	protected function register_controls() {

		// ── Content tab ───────────────────────────────────────────────────────

		$this->start_controls_section(
			'section_stock_content',
			array(
				'label' => esc_html__( 'Stock Messages', 'storzen' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);

		$this->add_control(
			'in_stock_message',
			array(
				'label'       => esc_html__( 'In Stock Message', 'storzen' ),
				'type'        => Controls_Manager::TEXT,
				'default'     => esc_html__( '✓ In Stock', 'storzen' ),
				'placeholder' => esc_html__( '✓ In Stock', 'storzen' ),
				'description' => esc_html__( 'Shown when the product is in stock and above the low-stock threshold.', 'storzen' ),
			)
		);

		$this->add_control(
			'low_stock_threshold',
			array(
				'label'       => esc_html__( 'Low Stock Threshold', 'storzen' ),
				'type'        => Controls_Manager::NUMBER,
				'min'         => 1,
				'max'         => 9999,
				'step'        => 1,
				'default'     => 10,
				'description' => esc_html__( 'Show the low-stock / urgency message when quantity is at or below this number (requires "Manage Stock" to be enabled on the product).', 'storzen' ),
			)
		);

		$this->add_control(
			'low_stock_message',
			array(
				'label'       => esc_html__( 'Low Stock Message', 'storzen' ),
				'type'        => Controls_Manager::TEXT,
				'default'     => esc_html__( 'Only {qty} left in stock!', 'storzen' ),
				'placeholder' => esc_html__( 'Only {qty} left in stock!', 'storzen' ),
				'description' => esc_html__( 'Use {qty} as placeholder for the actual quantity.', 'storzen' ),
			)
		);

		$this->add_control(
			'out_of_stock_message',
			array(
				'label'       => esc_html__( 'Out of Stock Message', 'storzen' ),
				'type'        => Controls_Manager::TEXT,
				'default'     => esc_html__( '✕ Out of Stock', 'storzen' ),
				'placeholder' => esc_html__( '✕ Out of Stock', 'storzen' ),
			)
		);

		$this->end_controls_section();

		// ── Progress bar section ──────────────────────────────────────────────

		$this->start_controls_section(
			'section_stock_bar',
			array(
				'label' => esc_html__( 'Progress Bar', 'storzen' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);

		$this->add_control(
			'show_progress_bar',
			array(
				'label'        => esc_html__( 'Show Stock Progress Bar', 'storzen' ),
				'type'         => Controls_Manager::SWITCHER,
				'label_on'     => esc_html__( 'Show', 'storzen' ),
				'label_off'    => esc_html__( 'Hide', 'storzen' ),
				'return_value' => 'yes',
				'default'      => 'yes',
				'description'  => esc_html__( 'Only shown when the product manages stock and quantity is at or below the low-stock threshold.', 'storzen' ),
			)
		);

		$this->add_control(
			'bar_max_stock',
			array(
				'label'       => esc_html__( 'Max Stock for 100% Bar', 'storzen' ),
				'type'        => Controls_Manager::NUMBER,
				'min'         => 1,
				'max'         => 9999,
				'step'        => 1,
				'default'     => 50,
				'description' => esc_html__( 'The quantity at which the progress bar shows 100%. Typically your initial / maximum stock level.', 'storzen' ),
				'condition'   => array( 'show_progress_bar' => 'yes' ),
			)
		);

		$this->end_controls_section();

		// ── Style tab ─────────────────────────────────────────────────────────

		$this->start_controls_section(
			'section_stock_style',
			array(
				'label' => esc_html__( 'Status Text', 'storzen' ),
				'tab'   => Controls_Manager::TAB_STYLE,
			)
		);

		$this->add_group_control(
			Group_Control_Typography::get_type(),
			array(
				'name'     => 'stock_typography',
				'selector' => '{{WRAPPER}} .sz-stock-status',
			)
		);

		$this->add_control(
			'in_stock_color',
			array(
				'label'     => esc_html__( 'In Stock Color', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '#27ae60',
				'selectors' => array(
					'{{WRAPPER}} .sz-stock-status.sz-stock-in' => 'color: {{VALUE}};',
				),
			)
		);

		$this->add_control(
			'low_stock_color',
			array(
				'label'     => esc_html__( 'Low Stock Color', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '#e74c3c',
				'selectors' => array(
					'{{WRAPPER}} .sz-stock-status.sz-stock-low' => 'color: {{VALUE}};',
				),
			)
		);

		$this->add_control(
			'out_of_stock_color',
			array(
				'label'     => esc_html__( 'Out of Stock Color', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '#95a5a6',
				'selectors' => array(
					'{{WRAPPER}} .sz-stock-status.sz-stock-out' => 'color: {{VALUE}};',
				),
			)
		);

		$this->add_responsive_control(
			'stock_margin',
			array(
				'label'      => esc_html__( 'Margin', 'storzen' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', 'em', 'rem' ),
				'selectors'  => array(
					'{{WRAPPER}} .sz-product-stock-widget' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			)
		);

		$this->end_controls_section();

		$this->start_controls_section(
			'section_stock_bar_style',
			array(
				'label'     => esc_html__( 'Progress Bar', 'storzen' ),
				'tab'       => Controls_Manager::TAB_STYLE,
				'condition' => array( 'show_progress_bar' => 'yes' ),
			)
		);

		$this->add_control(
			'bar_fill_color',
			array(
				'label'     => esc_html__( 'Bar Fill Color', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '#e74c3c',
				'selectors' => array(
					'{{WRAPPER}} .sz-stock-bar-fill' => 'background-color: {{VALUE}};',
				),
			)
		);

		$this->add_control(
			'bar_track_color',
			array(
				'label'     => esc_html__( 'Bar Track Color', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '#f0f0f0',
				'selectors' => array(
					'{{WRAPPER}} .sz-stock-bar-track' => 'background-color: {{VALUE}};',
				),
			)
		);

		$this->add_control(
			'bar_height',
			array(
				'label'      => esc_html__( 'Bar Height', 'storzen' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px' ),
				'range'      => array(
					'px' => array( 'min' => 2, 'max' => 20 ),
				),
				'default'    => array( 'unit' => 'px', 'size' => 6 ),
				'selectors'  => array(
					'{{WRAPPER}} .sz-stock-bar-track' => 'height: {{SIZE}}{{UNIT}}; border-radius: {{SIZE}}{{UNIT}};',
					'{{WRAPPER}} .sz-stock-bar-fill'  => 'height: {{SIZE}}{{UNIT}}; border-radius: {{SIZE}}{{UNIT}};',
				),
			)
		);

		$this->add_responsive_control(
			'bar_margin_top',
			array(
				'label'      => esc_html__( 'Margin Top', 'storzen' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px', 'em' ),
				'range'      => array(
					'px' => array( 'min' => 0, 'max' => 40 ),
				),
				'default'    => array( 'unit' => 'px', 'size' => 8 ),
				'selectors'  => array(
					'{{WRAPPER}} .sz-stock-bar-track' => 'margin-top: {{SIZE}}{{UNIT}};',
				),
			)
		);

		$this->end_controls_section();
	}

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

	protected function render() {

		if ( $this->szp_maybe_placeholder( esc_html__( 'Product Stock — visible on a single product page.', 'storzen' ) ) ) {
			return;
		}

		$product = $this->szp_get_loop_product();
		if ( ! $product ) {
			return;
		}

		$settings  = $this->get_settings_for_display();
		$manages   = $product->managing_stock();
		$status    = $product->get_stock_status(); // 'instock' | 'outofstock' | 'onbackorder'
		$qty       = $manages ? (int) $product->get_stock_quantity() : null;
		$threshold = max( 1, (int) ( $settings['low_stock_threshold'] ?? 10 ) );

		echo '<div class="sz-product-stock-widget">';

		if ( 'outofstock' === $status ) {

			// ── Out of stock ───────────────────────────────────────────────
			$msg = isset( $settings['out_of_stock_message'] ) && '' !== $settings['out_of_stock_message']
				? $settings['out_of_stock_message']
				: esc_html__( '✕ Out of Stock', 'storzen' );

			printf(
				'<span class="sz-stock-status sz-stock-out">%s</span>',
				esc_html( $msg )
			);

		} elseif ( $manages && null !== $qty && $qty <= $threshold ) {

			// ── Low stock / scarcity ───────────────────────────────────────
			$raw_msg = isset( $settings['low_stock_message'] ) && '' !== $settings['low_stock_message']
				? $settings['low_stock_message']
				: esc_html__( 'Only {qty} left in stock!', 'storzen' );

			$msg = str_replace( '{qty}', number_format_i18n( $qty ), $raw_msg );

			printf(
				'<span class="sz-stock-status sz-stock-low">%s</span>',
				esc_html( $msg )
			);

			// Progress bar.
			if ( 'yes' === ( $settings['show_progress_bar'] ?? 'yes' ) ) {
				$max = max( 1, (int) ( $settings['bar_max_stock'] ?? 50 ) );
				$pct = min( 100, round( ( $qty / $max ) * 100 ) );
				printf(
					'<div class="sz-stock-bar-track" role="progressbar" aria-valuenow="%1$d" aria-valuemin="0" aria-valuemax="%2$d" aria-label="%3$s">'
					. '<div class="sz-stock-bar-fill" style="width:%4$d%%"></div>'
					. '</div>',
					absint( $qty ),
					absint( $max ),
					/* translators: %d: remaining stock quantity */
					esc_attr( sprintf( __( '%d items remaining', 'storzen' ), $qty ) ),
					absint( $pct )
				);
			}

		} else {

			// ── In stock ───────────────────────────────────────────────────
			$msg = isset( $settings['in_stock_message'] ) && '' !== $settings['in_stock_message']
				? $settings['in_stock_message']
				: esc_html__( '✓ In Stock', 'storzen' );

			printf(
				'<span class="sz-stock-status sz-stock-in">%s</span>',
				esc_html( $msg )
			);
		}

		echo '</div><!-- .sz-product-stock-widget -->';
	}
}


// ─────────────────────────────────────────────────────────────────────────────
// Widget 3: Upsell Products
// ─────────────────────────────────────────────────────────────────────────────

/**
 * Product upsell slider / grid widget.
 *
 * Renders upsell products defined on the current product via
 * WC_Product::get_upsell_ids(). Supports both a responsive CSS Grid layout
 * and a Swiper-powered carousel. Uses wc_get_products() (HPOS-safe) and the
 * existing Swiper bundle already registered by Storzen so no new JS dependency
 * is introduced.
 *
 * Toggle key:  product_upsells
 * Category:    storzen-product-details
 *
 * @since 1.2.0
 */
class Storzen_Product_Upsells_Widget extends Widget_Base {

	use Storzen_Product_Part_Helpers;

	// ── Identity ──────────────────────────────────────────────────────────────

	public function get_name() {
		return 'storzen-product-upsells';
	}

	public function get_title() {
		return esc_html__( 'Upsell Products', 'storzen' );
	}

	public function get_icon() {
		return 'eicon-product-upsell';
	}

	public function get_categories() {
		return array( 'storzen-product-details' );
	}

	public function get_keywords() {
		return array( 'upsell', 'related', 'cross-sell', 'recommendations', 'product', 'storzen' );
	}

	// ── Controls ──────────────────────────────────────────────────────────────

	protected function register_controls() {

		// ── Content tab ───────────────────────────────────────────────────────

		$this->start_controls_section(
			'section_upsells_content',
			array(
				'label' => esc_html__( 'Upsell Products', 'storzen' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);

		$this->add_control(
			'section_title',
			array(
				'label'       => esc_html__( 'Section Title', 'storzen' ),
				'type'        => Controls_Manager::TEXT,
				'default'     => esc_html__( 'You Might Also Like', 'storzen' ),
				'placeholder' => esc_html__( 'You Might Also Like', 'storzen' ),
				'description' => esc_html__( 'Leave empty to hide the title.', 'storzen' ),
			)
		);

		$this->add_control(
			'title_tag',
			array(
				'label'   => esc_html__( 'Title HTML Tag', 'storzen' ),
				'type'    => Controls_Manager::SELECT,
				'default' => 'h2',
				'options' => array(
					'h2' => 'H2',
					'h3' => 'H3',
					'h4' => 'H4',
					'h5' => 'H5',
					'h6' => 'H6',
				),
			)
		);

		$this->add_control(
			'limit',
			array(
				'label'       => esc_html__( 'Max Upsell Products', 'storzen' ),
				'type'        => Controls_Manager::NUMBER,
				'min'         => 1,
				'max'         => 12,
				'step'        => 1,
				'default'     => 4,
				'description' => esc_html__( 'Maximum number of upsell products to display. Upsells are assigned in the Linked Products tab of the product editor.', 'storzen' ),
			)
		);

		$this->add_control(
			'layout',
			array(
				'label'   => esc_html__( 'Layout', 'storzen' ),
				'type'    => Controls_Manager::SELECT,
				'default' => 'grid',
				'options' => array(
					'grid'     => esc_html__( 'Grid', 'storzen' ),
					'carousel' => esc_html__( 'Carousel / Slider', 'storzen' ),
				),
			)
		);

		$this->add_responsive_control(
			'columns',
			array(
				'label'          => esc_html__( 'Columns', 'storzen' ),
				'type'           => Controls_Manager::SELECT,
				'default'        => '4',
				'tablet_default' => '3',
				'mobile_default' => '2',
				'options'        => array(
					'1' => '1',
					'2' => '2',
					'3' => '3',
					'4' => '4',
					'5' => '5',
				),
				'selectors'      => array(
					'{{WRAPPER}} .sz-upsells-grid' => 'grid-template-columns: repeat({{VALUE}}, 1fr);',
				),
				'condition'      => array( 'layout' => 'grid' ),
			)
		);

		$this->add_control(
			'gap',
			array(
				'label'      => esc_html__( 'Card Gap', 'storzen' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px' ),
				'range'      => array( 'px' => array( 'min' => 0, 'max' => 60 ) ),
				'default'    => array( 'unit' => 'px', 'size' => 20 ),
				'selectors'  => array(
					'{{WRAPPER}} .sz-upsells-grid' => 'gap: {{SIZE}}{{UNIT}};',
				),
				'condition'  => array( 'layout' => 'grid' ),
			)
		);

		$this->end_controls_section();

		// ── Card elements ─────────────────────────────────────────────────────

		$this->start_controls_section(
			'section_upsells_card',
			array(
				'label' => esc_html__( 'Card Elements', 'storzen' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);

		$this->add_control(
			'show_price',
			array(
				'label'        => esc_html__( 'Show Price', 'storzen' ),
				'type'         => Controls_Manager::SWITCHER,
				'label_on'     => esc_html__( 'Show', 'storzen' ),
				'label_off'    => esc_html__( 'Hide', 'storzen' ),
				'return_value' => 'yes',
				'default'      => 'yes',
			)
		);

		$this->add_control(
			'show_rating',
			array(
				'label'        => esc_html__( 'Show Rating', 'storzen' ),
				'type'         => Controls_Manager::SWITCHER,
				'label_on'     => esc_html__( 'Show', 'storzen' ),
				'label_off'    => esc_html__( 'Hide', 'storzen' ),
				'return_value' => 'yes',
				'default'      => 'yes',
			)
		);

		$this->add_control(
			'show_add_to_cart',
			array(
				'label'        => esc_html__( 'Show Add to Cart', 'storzen' ),
				'type'         => Controls_Manager::SWITCHER,
				'label_on'     => esc_html__( 'Show', 'storzen' ),
				'label_off'    => esc_html__( 'Hide', 'storzen' ),
				'return_value' => 'yes',
				'default'      => 'yes',
			)
		);

		$this->add_control(
			'image_size',
			array(
				'label'   => esc_html__( 'Thumbnail Size', 'storzen' ),
				'type'    => Controls_Manager::SELECT,
				'default' => 'woocommerce_thumbnail',
				'options' => array(
					'woocommerce_thumbnail' => esc_html__( 'WooCommerce Thumbnail', 'storzen' ),
					'woocommerce_single'    => esc_html__( 'WooCommerce Single', 'storzen' ),
					'medium'                => esc_html__( 'Medium', 'storzen' ),
					'large'                 => esc_html__( 'Large', 'storzen' ),
				),
			)
		);

		$this->end_controls_section();

		// ── Style tab ─────────────────────────────────────────────────────────

		$this->start_controls_section(
			'section_upsells_style_title',
			array(
				'label' => esc_html__( 'Section Title', 'storzen' ),
				'tab'   => Controls_Manager::TAB_STYLE,
			)
		);

		$this->add_control(
			'title_color',
			array(
				'label'     => esc_html__( 'Color', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'selectors' => array(
					'{{WRAPPER}} .sz-upsells-section-title' => 'color: {{VALUE}};',
				),
			)
		);

		$this->add_group_control(
			Group_Control_Typography::get_type(),
			array(
				'name'     => 'title_typography',
				'selector' => '{{WRAPPER}} .sz-upsells-section-title',
			)
		);

		$this->add_responsive_control(
			'title_margin',
			array(
				'label'      => esc_html__( 'Margin Bottom', 'storzen' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px', 'em' ),
				'range'      => array( 'px' => array( 'min' => 0, 'max' => 60 ) ),
				'default'    => array( 'unit' => 'px', 'size' => 24 ),
				'selectors'  => array(
					'{{WRAPPER}} .sz-upsells-section-title' => 'margin-bottom: {{SIZE}}{{UNIT}};',
				),
			)
		);

		$this->end_controls_section();

		$this->start_controls_section(
			'section_upsells_style_card',
			array(
				'label' => esc_html__( 'Product Card', 'storzen' ),
				'tab'   => Controls_Manager::TAB_STYLE,
			)
		);

		$this->add_control(
			'card_bg',
			array(
				'label'     => esc_html__( 'Background', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'selectors' => array(
					'{{WRAPPER}} .sz-upsell-card' => 'background-color: {{VALUE}};',
				),
			)
		);

		$this->add_group_control(
			Group_Control_Border::get_type(),
			array(
				'name'     => 'card_border',
				'selector' => '{{WRAPPER}} .sz-upsell-card',
			)
		);

		$this->add_control(
			'card_border_radius',
			array(
				'label'      => esc_html__( 'Border Radius', 'storzen' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px', '%' ),
				'range'      => array( 'px' => array( 'min' => 0, 'max' => 30 ) ),
				'default'    => array( 'unit' => 'px', 'size' => 8 ),
				'selectors'  => array(
					'{{WRAPPER}} .sz-upsell-card' => 'border-radius: {{SIZE}}{{UNIT}};',
				),
			)
		);

		$this->add_responsive_control(
			'card_padding',
			array(
				'label'      => esc_html__( 'Padding', 'storzen' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', 'em' ),
				'default'    => array(
					'top'    => '12',
					'right'  => '12',
					'bottom' => '12',
					'left'   => '12',
					'unit'   => 'px',
				),
				'selectors'  => array(
					'{{WRAPPER}} .sz-upsell-card__body' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			)
		);

		$this->end_controls_section();

		$this->start_controls_section(
			'section_upsells_style_atc',
			array(
				'label'     => esc_html__( 'Add to Cart Button', 'storzen' ),
				'tab'       => Controls_Manager::TAB_STYLE,
				'condition' => array( 'show_add_to_cart' => 'yes' ),
			)
		);

		$this->add_control(
			'atc_bg_color',
			array(
				'label'     => esc_html__( 'Background', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '#FF3636',
				'selectors' => array(
					'{{WRAPPER}} .sz-upsell-atc' => 'background-color: {{VALUE}}; border-color: {{VALUE}};',
				),
			)
		);

		$this->add_control(
			'atc_text_color',
			array(
				'label'     => esc_html__( 'Text Color', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '#ffffff',
				'selectors' => array(
					'{{WRAPPER}} .sz-upsell-atc' => 'color: {{VALUE}};',
				),
			)
		);

		$this->add_control(
			'atc_hover_bg_color',
			array(
				'label'     => esc_html__( 'Hover Background', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'selectors' => array(
					'{{WRAPPER}} .sz-upsell-atc:hover' => 'background-color: {{VALUE}}; border-color: {{VALUE}};',
				),
			)
		);

		$this->add_control(
			'atc_border_radius',
			array(
				'label'      => esc_html__( 'Border Radius', 'storzen' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px', '%' ),
				'range'      => array( 'px' => array( 'min' => 0, 'max' => 50 ) ),
				'default'    => array( 'unit' => 'px', 'size' => 4 ),
				'selectors'  => array(
					'{{WRAPPER}} .sz-upsell-atc' => 'border-radius: {{SIZE}}{{UNIT}};',
				),
			)
		);

		$this->end_controls_section();
	}

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

	protected function render() {

		if ( $this->szp_maybe_placeholder( esc_html__( 'Upsell Products — visible on a single product page that has upsells defined.', 'storzen' ) ) ) {
			return;
		}

		$main_product = $this->szp_get_loop_product();
		if ( ! $main_product ) {
			return;
		}

		$upsell_ids = $main_product->get_upsell_ids();

		if ( empty( $upsell_ids ) ) {
			// In editor: polite empty-state. On frontend: render nothing (no spare DOM).
			$ed = \Elementor\Plugin::$instance->editor;
			if ( $ed && method_exists( $ed, 'is_edit_mode' ) && $ed->is_edit_mode() ) {
				printf(
					'<div class="szp-product-part-placeholder" style="padding:16px;border:1px dashed #ccc;border-radius:6px;background:#f9f9f9;font-size:13px;color:#555;">%s</div>',
					esc_html__( 'No upsell products are defined for this product. Add them in the Linked Products tab of the product editor.', 'storzen' )
				);
			}
			return;
		}

		$settings   = $this->get_settings_for_display();
		$limit      = max( 1, (int) ( $settings['limit'] ?? 4 ) );
		$layout     = in_array( $settings['layout'] ?? 'grid', array( 'grid', 'carousel' ), true )
			? $settings['layout']
			: 'grid';
		$img_size   = sanitize_text_field( $settings['image_size'] ?? 'woocommerce_thumbnail' );
		$show_price = 'yes' === ( $settings['show_price'] ?? 'yes' );
		$show_rating = 'yes' === ( $settings['show_rating'] ?? 'yes' );
		$show_atc   = 'yes' === ( $settings['show_add_to_cart'] ?? 'yes' );

		// Slice to limit before querying.
		$upsell_ids = array_slice( $upsell_ids, 0, $limit );

		// Use wc_get_products() — HPOS-compatible. Filter to published + visible.
		$upsells = wc_get_products(
			array(
				'include' => array_map( 'absint', $upsell_ids ),
				'limit'   => $limit,
				'status'  => 'publish',
			)
		);

		// Keep only purchasable, visible products; preserve the upsell order.
		$ordered = array();
		foreach ( $upsell_ids as $id ) {
			foreach ( $upsells as $p ) {
				if ( (int) $p->get_id() === (int) $id && $p->is_visible() ) {
					$ordered[] = $p;
					break;
				}
			}
		}

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

		echo '<div class="sz-product-upsells-widget">';

		// ── Section title ──────────────────────────────────────────────────
		$title = isset( $settings['section_title'] ) ? trim( (string) $settings['section_title'] ) : '';
		if ( $title !== '' ) {
			$tag = isset( $settings['title_tag'] ) ? sanitize_key( $settings['title_tag'] ) : 'h2';
			if ( ! in_array( $tag, array( 'h2', 'h3', 'h4', 'h5', 'h6' ), true ) ) {
				$tag = 'h2';
			}
			printf(
				'<%1$s class="sz-upsells-section-title">%2$s</%1$s>',
				esc_attr( $tag ),
				esc_html( $title )
			);
		}

		// ── Layout wrapper ─────────────────────────────────────────────────
		if ( 'carousel' === $layout ) {
			// Use the Swiper bundle already registered in class-storzen-init.php.
			$wrapper_id = 'sz-upsells-' . uniqid();
			printf( '<div class="sz-upsells-carousel swiper" id="%s">', esc_attr( $wrapper_id ) );
			echo '<div class="swiper-wrapper">';
		} else {
			echo '<div class="sz-upsells-grid">';
		}

		foreach ( $ordered as $upsell ) {
			/** @var \WC_Product $upsell */

			if ( 'carousel' === $layout ) {
				echo '<div class="swiper-slide">';
			}

			$this->render_upsell_card( $upsell, $img_size, $show_price, $show_rating, $show_atc );

			if ( 'carousel' === $layout ) {
				echo '</div><!-- .swiper-slide -->';
			}
		}

		echo '</div>'; // swiper-wrapper or sz-upsells-grid

		if ( 'carousel' === $layout ) {
			echo '<div class="swiper-button-prev" aria-label="' . esc_attr__( 'Previous', 'storzen' ) . '"></div>';
			echo '<div class="swiper-button-next" aria-label="' . esc_attr__( 'Next', 'storzen' ) . '"></div>';
			echo '<div class="swiper-pagination"></div>';
			echo '</div><!-- .sz-upsells-carousel -->';

			// Inline init: re-uses the already-loaded swiper-bundle.min.js.
			// We set breakpoints conservatively; the Elementor columns control
			// governs grid layout, so we keep carousel responsive as well.
			$cols         = max( 1, (int) ( $settings['columns'] ?? 4 ) );
			$cols_tablet  = max( 1, $cols - 1 );
			$cols_mobile  = min( 2, $cols );
			?>
			<script>
			( function () {
				var el = document.getElementById( <?php echo wp_json_encode( $wrapper_id ); ?> );
				if ( ! el || typeof Swiper === 'undefined' ) { return; }
				new Swiper( el, {
					slidesPerView: <?php echo (int) $cols; ?>,
					spaceBetween: 20,
					navigation: {
						nextEl: el.querySelector( '.swiper-button-next' ),
						prevEl: el.querySelector( '.swiper-button-prev' ),
					},
					pagination: {
						el:        el.querySelector( '.swiper-pagination' ),
						clickable: true,
					},
					breakpoints: {
						0:   { slidesPerView: 1 },
						480: { slidesPerView: <?php echo (int) $cols_mobile; ?> },
						768: { slidesPerView: <?php echo (int) $cols_tablet; ?> },
						1024:{ slidesPerView: <?php echo (int) $cols; ?> },
					},
					a11y: {
						prevSlideMessage: <?php echo wp_json_encode( esc_html__( 'Previous slide', 'storzen' ) ); ?>,
						nextSlideMessage: <?php echo wp_json_encode( esc_html__( 'Next slide', 'storzen' ) ); ?>,
					},
				} );
			}() );
			</script>
			<?php
		}

		echo '</div><!-- .sz-product-upsells-widget -->';
	}

	// ── Card helper ───────────────────────────────────────────────────────────

	/**
	 * Render a single upsell product card.
	 *
	 * @param \WC_Product $product
	 * @param string      $img_size    WP image size string.
	 * @param bool        $show_price
	 * @param bool        $show_rating
	 * @param bool        $show_atc
	 */
	private function render_upsell_card(
		\WC_Product $product,
		string $img_size,
		bool $show_price,
		bool $show_rating,
		bool $show_atc
	) {
		$pid       = (int) $product->get_id();
		$permalink = get_permalink( $pid );
		$name      = $product->get_name();

		echo '<div class="sz-upsell-card">';

		// Thumbnail.
		printf(
			'<a href="%1$s" class="sz-upsell-card__thumb" aria-label="%2$s">%3$s</a>',
			esc_url( $permalink ),
			esc_attr( $name ),
			wp_kses_post( $product->get_image( $img_size ) )
		);

		echo '<div class="sz-upsell-card__body">';

		// Product name.
		printf(
			'<h3 class="sz-upsell-card__name"><a href="%1$s">%2$s</a></h3>',
			esc_url( $permalink ),
			esc_html( $name )
		);

		// Price.
		if ( $show_price ) {
			printf(
				'<div class="sz-upsell-card__price">%s</div>',
				wp_kses_post( $product->get_price_html() )
			);
		}

		// Star rating (only when there are reviews).
		if ( $show_rating && $product->get_review_count() > 0 ) {
			printf(
				'<div class="sz-upsell-card__rating">%s</div>',
				wp_kses_post(
					wc_get_rating_html(
						(float) $product->get_average_rating(),
						(int) $product->get_review_count()
					)
				)
			);
		}

		// Add to cart / View button.
		if ( $show_atc ) {
			if ( $product->is_purchasable() && $product->is_in_stock() && $product->is_type( 'simple' ) ) {
				printf(
					'<a href="%1$s" class="button product_type_simple add_to_cart_button ajax_add_to_cart sz-upsell-atc" data-product_id="%2$d" data-quantity="1" rel="nofollow" aria-label="%3$s">%4$s</a>',
					esc_url( $product->add_to_cart_url() ),
					absint( $pid ),
					/* translators: %s: product name */
					esc_attr( sprintf( __( 'Add %s to cart', 'storzen' ), $name ) ),
					esc_html( $product->add_to_cart_text() )
				);
			} else {
				// Variable, grouped, external, or out-of-stock → link to product page.
				printf(
					'<a href="%1$s" class="button sz-upsell-atc" aria-label="%2$s">%3$s</a>',
					esc_url( $permalink ),
					/* translators: %s: product name */
					esc_attr( sprintf( __( 'View %s', 'storzen' ), $name ) ),
					esc_html( $product->add_to_cart_text() )
				);
			}
		}

		echo '</div><!-- .sz-upsell-card__body -->';
		echo '</div><!-- .sz-upsell-card -->';
	}
}
