<?php
/**
 * Storzen Module — Sale Badge
 *
 * Automatically shows dynamic badges on WooCommerce product cards:
 *   • SALE  — % discount when sale price is set
 *   • NEW   — for products added within X days
 *   • HOT   — for bestsellers (top-selling products)
 *   • OUT   — out-of-stock indicator
 *
 * Zero template overrides. Uses WooCommerce action hooks.
 * Supports: Simple products, Variable products (shows highest discount).
 * Performance: Bestseller list cached via transient (24h).
 *
 * @package storzen
 * @since   1.1.0
 */

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

if ( ! class_exists( 'Storzen_Module_Sale_Badge' ) ) {

	class Storzen_Module_Sale_Badge {

		/** Transient key for hot-products list */
		const HOT_TRANSIENT = 'storzen_hot_products';

		/** How many top sellers qualify as "HOT" */
		const HOT_LIMIT = 10;

		public function __construct() {
			// Remove WooCommerce default "Sale!" badge
			remove_action( 'woocommerce_before_shop_loop_item_title', 'woocommerce_show_product_loop_sale_flash', 10 );
			remove_action( 'woocommerce_before_single_product_summary', 'woocommerce_show_product_sale_flash', 10 );

			// Inject our custom badge — listen on BOTH WooCommerce default hooks
			// (works with any standard WC theme) AND Storzen-native hooks (works
			// with imported Storzen Elementor templates).
			add_action( 'woocommerce_before_shop_loop_item_title',   array( $this, 'render_badges' ), 10 );
			add_action( 'woocommerce_before_single_product_summary', array( $this, 'render_badges' ), 10 );
			add_action( 'storzen_shop_card_badges',              array( $this, 'render_badges' ), 10, 1 );
			add_action( 'storzen_product_single_after_price',    array( $this, 'render_badges' ), 10, 1 );

			// Enqueue lightweight badge CSS
			add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ) );

			// Clear hot-products cache when an order is completed
			add_action( 'woocommerce_order_status_completed', array( $this, 'clear_hot_cache' ) );
		}

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

		public function enqueue_assets() {
			if ( is_admin() ) {
				return;
			}
			wp_enqueue_style(
				'storzen-sale-badge',
				STORZEN_ROOT_URL . 'assets/css/modules/sale-badge.css',
				array(),
				STORZEN_VERSION
			);
		}

		// ── Badge Rendering ───────────────────────────────────────────────

		public function render_badges( $product_arg = null ) {
			if ( class_exists( 'Elementor\Storzen_Archive_Grid' ) ) {
				$ctx = \Elementor\Storzen_Archive_Grid::is_module_active( 'sale_badge' );
				if ( false === $ctx ) {
					return;
				}
			}
			$product = ( $product_arg instanceof WC_Product ) ? $product_arg : ( $GLOBALS['product'] ?? null );
			if ( ! $product instanceof WC_Product ) {
				return;
			}

			$badges = $this->get_badges_for_product( $product );
			if ( empty( $badges ) ) {
				return;
			}

			$style = sanitize_key(
				storzen_module_setting( 'sale_badge', 'badge_style' ) ?: 'rounded'
			);

			echo '<div class="sz-badge-wrap sz-badge-style-' . esc_attr( $style ) . '">';
			foreach ( $badges as $badge ) {
				printf(
					'<span class="sz-badge sz-badge--%s">%s</span>',
					esc_attr( $badge['type'] ),
					esc_html( $badge['label'] )
				);
			}
			echo '</div>';
		}

		/**
		 * Build badge list for a product.
		 *
		 * @param WC_Product $product
		 * @return array  Array of ['type' => string, 'label' => string]
		 */
		private function get_badges_for_product( WC_Product $product ) {
			$badges = array();

			// 1. SALE badge (with optional % discount)
			if ( $product->is_on_sale() ) {
				$discount = $this->get_discount_percentage( $product );
				if ( $discount && (bool) storzen_module_setting( 'sale_badge', 'show_discount_pct' ) ) {
					$label = sprintf(
						/* translators: %d: discount percentage */
						__( '-%d%%', 'storzen' ),
						$discount
					);
				} else {
					$label = __( 'Sale', 'storzen' );
				}
				$badges[] = array( 'type' => 'sale', 'label' => $label );
			}

			// 2. OUT OF STOCK
			if ( ! $product->is_in_stock() ) {
				$badges[] = array( 'type' => 'out', 'label' => __( 'Out of Stock', 'storzen' ) );
				return $badges; // No point showing NEW/HOT if out of stock
			}

			// 3. NEW badge — based on date published
			$new_days = absint( storzen_module_setting( 'sale_badge', 'new_badge_days' ) ?: 30 );
			if ( $new_days > 0 ) {
				$published = get_post_datetime( $product->get_id(), 'date', 'gmt' );
				if ( $published ) {
					$diff = ( new DateTime( 'now', new DateTimeZone( 'UTC' ) ) )->diff( $published );
					if ( $diff->days <= $new_days ) {
						$badges[] = array( 'type' => 'new', 'label' => __( 'New', 'storzen' ) );
					}
				}
			}

			// 4. HOT badge — top sellers
			$hot_ids = $this->get_hot_product_ids();
			if ( in_array( $product->get_id(), $hot_ids, true ) ) {
				$badges[] = array( 'type' => 'hot', 'label' => __( 'Hot', 'storzen' ) );
			}

			return $badges;
		}

		/**
		 * Calculate discount percentage.
		 * For variable products, uses the highest discount across variations.
		 *
		 * @param WC_Product $product
		 * @return int|null  Integer 1-99, or null if not calculable
		 */
		private function get_discount_percentage( WC_Product $product ) {
			if ( $product->is_type( 'variable' ) ) {
				$max_discount = 0;
				foreach ( $product->get_available_variations() as $variation_data ) {
					$variation = wc_get_product( $variation_data['variation_id'] );
					if ( ! $variation ) continue;
					$regular = (float) $variation->get_regular_price();
					$sale    = (float) $variation->get_sale_price();
					if ( $regular > 0 && $sale > 0 && $sale < $regular ) {
						$discount = (int) round( ( ( $regular - $sale ) / $regular ) * 100 );
						$max_discount = max( $max_discount, $discount );
					}
				}
				return $max_discount > 0 ? $max_discount : null;
			}

			$regular = (float) $product->get_regular_price();
			$sale    = (float) $product->get_sale_price();
			if ( $regular > 0 && $sale > 0 && $sale < $regular ) {
				return (int) round( ( ( $regular - $sale ) / $regular ) * 100 );
			}
			return null;
		}

		/**
		 * Get top-selling product IDs (cached 24h).
		 *
		 * @return int[]
		 */
		private function get_hot_product_ids() {
			$cached = get_transient( self::HOT_TRANSIENT );
			if ( false !== $cached ) {
				return $cached;
			}

			$query = new WC_Product_Query( array(
				'limit'   => self::HOT_LIMIT,
				'orderby' => 'total_sales',
				'order'   => 'DESC',
				'return'  => 'ids',
				'status'  => 'publish',
			) );

			$ids = $query->get_products();
			$ids = array_map( 'absint', $ids );

			set_transient( self::HOT_TRANSIENT, $ids, DAY_IN_SECONDS );
			return $ids;
		}

		/**
		 * Clear hot-products transient on new order completion.
		 */
		public function clear_hot_cache() {
			delete_transient( self::HOT_TRANSIENT );
		}

	} // end class

} // end class_exists
