<?php
/**
 * Mystery Box Product Class.
 *
 * Defines the custom WooCommerce product type "mysterx" (Mystery Box),
 * including stock management, box opening logic, and reward tracking.
 *
 * @link       https://wpgenie.org
 * @since      1.0.0
 *
 * @package    Mysterx
 * @subpackage Mysterx/includes
 */

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

/**
 * Class Mysterx_Product
 *
 * @since 1.0.0
 */
class Mysterx_Product extends WC_Product {

	/**
	 * Post type.
	 *
	 * @var string
	 */
	public $post_type = 'product';

	/**
	 * Product type.
	 *
	 * @var string
	 */
	public $product_type = 'mysterx';

	/**
	 * Stores product data.
	 *
	 * @var array
	 */
	protected $extra_data = array();

	/**
	 * __construct function.
	 *
	 * @access public
	 * @param mixed $product Product object.
	 */
	public function __construct( $product ) {

		if ( is_array( $this->data ) ) {
			$this->data = array_merge( $this->data, $this->extra_data );
		}

		parent::__construct( $product );
	}

	/**
	 * Get internal type.
	 *
	 * @return string
	 */
	public function get_type() {
		return 'mysterx';
	}

	/**
	 * Get the add to url used mainly in loops.
	 *
	 * @return string
	 */
	public function add_to_cart_url() {
		global $myster_opening;
		$url = $this->is_purchasable() && $this->is_in_stock() ? remove_query_arg(
			'added-to-cart',
			add_query_arg(
				array(
					'add-to-cart' => $this->get_id(),
				),
				( function_exists( 'is_feed' ) && is_feed() ) || ( function_exists( 'is_404' ) && is_404() ) ? $this->get_permalink() : false
			)
		) : $this->get_permalink();
		if ( true === $myster_opening ) {
			$url = add_query_arg(
				array(
					'openbox' => $this->get_id(),
				),
				$this->get_permalink()
			);
		}
		return apply_filters( 'woocommerce_product_add_to_cart_url', $url, $this );
	}

	/**
	 * Get the add to cart button text.
	 *
	 * @return string
	 */
	public function add_to_cart_text() {
		global $myster_opening;

		if ( true === $myster_opening ) {
			$text = __( 'Open', 'mysterx-mystery-boxes-for-woocommerce' );
		} else {
			$text = $this->is_purchasable() && $this->is_in_stock() ? __( 'Add to cart', 'mysterx-mystery-boxes-for-woocommerce' ) : __( 'Read more', 'mysterx-mystery-boxes-for-woocommerce' );
		}

		return apply_filters( 'woocommerce_product_add_to_cart_text', $text, $this );
	}

	/**
	 * Get the add to cart button text description - used in aria tags.
	 *
	 * @since 3.3.0
	 * @return string
	 */
	public function add_to_cart_description() {
		/* translators: %s: Product title */
		$text = $this->is_purchasable() && $this->is_in_stock() ? __( 'Add to cart: &ldquo;%s&rdquo;', 'mysterx-mystery-boxes-for-woocommerce' ) : __( 'Read more about &ldquo;%s&rdquo;', 'mysterx-mystery-boxes-for-woocommerce' );

		return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( $text, $this->get_name() ), $this );
	}

	/**
	 * Get the add to cart button success message - used to update the mini cart live region.
	 *
	 * @return string
	 */
	public function add_to_cart_success_message() {
		$text = '';

		if ( $this->is_purchasable() && $this->is_in_stock() ) {
			/* translators: %s: Product title */
			$text = __( '&ldquo;%s&rdquo; has been added to your cart', 'mysterx-mystery-boxes-for-woocommerce' );
			$text = sprintf( $text, $this->get_name() );
		}

		/**
		 * Filter product add to cart success message.
		 *
		 * @since 9.2.0
		 * @param string $text The success message when a product is added to the cart.
		 * @param WC_Product_Simple $this Reference to the current WC_Product_Simple instance.
		 */
		return apply_filters( 'woocommerce_product_add_to_cart_success_message', $text, $this );
	}

	/**
	 * Returns number of items available for sale.
	 *
	 * @param  string $context What the value is for. Valid values are view and edit.
	 * @return int|null
	 */
	public function get_stock_quantity( $context = 'view' ) {

		global $wpdb;

		$results = wp_cache_get( 'mysterx_get_get_stock_quantity_for_product' . $this->get_id(), 'mysterx' );

		if ( false === $results || 'edit' === $context ) {

			$total_qty = $wpdb->get_var(
				$wpdb->prepare(
					'SELECT SUM(qty) FROM %i WHERE product_id = %d',
					MYSTERX_TBL_ITEMS,
					$this->get_id()
				)
			);

			$claimed_qty = $wpdb->get_var(
				$wpdb->prepare(
					'SELECT COUNT(id) FROM %i WHERE product_id = %d',
					MYSTERX_TBL_LOG,
					$this->get_id()
				)
			);

			$results = intval( $total_qty ) - intval( $claimed_qty );
			wp_cache_set( 'mysterx_get_get_stock_quantity_for_product' . $this->get_id(), $results, 'mysterx' );
		}
		return intval( $results );
	}

	/**
	 * Check if there is enough items for the product.
	 *
	 * @return bool
	 */
	public function has_enough_items() {
		$stock_quantity = $this->get_stock_quantity();
		if ( is_null( $stock_quantity ) ) {
			return true;
		}
		return $stock_quantity > 0;
	}

	/**
	 * Check if the product is in stock.
	 *
	 * @return bool
	 */
	public function is_in_stock() {
		return $this->has_enough_items();
	}

	/**
	 * Get the number of boxes for opening for a user.
	 *
	 * @param int $user_id User ID.
	 * @return int Number of boxes for opening.
	 */
	public function get_number_of_boxses_for_openning_for_user( $user_id ) {
		global $wpdb;

		$results = $wpdb->get_var(
			$wpdb->prepare(
				'SELECT COUNT(1)
		        FROM %i as l
				LEFT JOIN %i as o ON l.id = o.id
				WHERE l.user_id = %d
				  AND l.product_id = %d
				  AND o.opened_at IS NULL',
				MYSTERX_TBL_LOG,
				MYSTERX_TBL_OPEN_LOG,
				$user_id,
				$this->get_id(),
			)
		);
		return intval( $results );
	}

	/**
	 * Get the URL for opening the box.
	 *
	 * @return string URL for opening the box.
	 */
	public function open_box_url() {
		return add_query_arg(
			array(
				'openbox' => $this->get_id(),
			),
			$this->get_permalink()
		);
	}

	/**
	 * Get count of opened rewards for product
	 *
	 * @return object counts of opened rewards
	 */
	public function get_count_of_opened_rewards() {
		global $wpdb;

		$counts_raw = $wpdb->get_results(
			$wpdb->prepare(
				'SELECT reward_id, COUNT(*) as total_used
			FROM %i
			WHERE product_id = %d
			GROUP BY reward_id',
				MYSTERX_TBL_OPEN_LOG,
				$this->get_id()
			),
			OBJECT_K
		);
		return $counts_raw;
	}

	/**
	 * Check if there is any reward for the product
	 *
	 * @return boolean
	 */
	public function is_there_reward() {
		$items = mysterx_get_items_for_product( $this->get_id() );
		return ! empty( $items );
	}
}
