<?php
/**
 * Card Oracle WooCommerce integration.
 *
 * Lets a Card Oracle reading be gated behind a WooCommerce product
 * purchase. Each reading can be linked to a WC product via the
 * _co_wc_product_id meta; until the current customer has a completed
 * order containing that product, the reading shortcode renders a
 * "Buy this reading" gate instead of the selection screen.
 *
 * @package CardOracle
 * @since   1.2.6
 */

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

/**
 * Class Card_Oracle_WC
 *
 * Loaded unconditionally so static helpers can be called even when WC isn't
 * active — every method that touches WC APIs first checks is_active().
 *
 * @since 1.2.6
 */
class Card_Oracle_WC {

	/**
	 * Whether WooCommerce is loaded on this site.
	 *
	 * @since 1.2.6
	 * @return bool
	 */
	public static function is_active() {
		return class_exists( 'WooCommerce' );
	}

	/**
	 * Get the WC product linked to a reading, if any.
	 *
	 * @since 1.2.6
	 * @param int $reading_id Reading post ID.
	 * @return int Product post ID, or 0 when not linked.
	 */
	public static function get_linked_product_id( $reading_id ) {
		if ( ! function_exists( 'get_post_meta' ) ) {
			return 0;
		}
		$product_id = (int) get_post_meta( $reading_id, CO_WC_PRODUCT_ID, true );
		return $product_id > 0 ? $product_id : 0;
	}

	/**
	 * Check whether the current customer has already purchased the linked product.
	 *
	 * Uses WC's wc_customer_bought_product() so we don't reinvent order querying.
	 * For guest visitors with no session email, returns false.
	 *
	 * @since 1.2.6
	 * @param int $product_id WooCommerce product post ID.
	 * @return bool True when an order containing $product_id has reached "completed".
	 */
	public static function customer_has_purchased( $product_id ) {
		if ( ! self::is_active() || $product_id <= 0 ) {
			return false;
		}
		if ( ! function_exists( 'wc_customer_bought_product' ) ) {
			return false;
		}

		$user_id = function_exists( 'get_current_user_id' ) ? (int) get_current_user_id() : 0;
		$email   = '';

		if ( $user_id > 0 && function_exists( 'wp_get_current_user' ) ) {
			$user = wp_get_current_user();
			if ( $user && isset( $user->user_email ) ) {
				$email = (string) $user->user_email;
			}
		}

		if ( '' === $email && function_exists( 'WC' ) && WC() && isset( WC()->customer ) && is_object( WC()->customer ) && method_exists( WC()->customer, 'get_billing_email' ) ) {
			$email = (string) WC()->customer->get_billing_email();
		}

		if ( '' === $email && 0 === $user_id ) {
			return false;
		}

		return (bool) wc_customer_bought_product( $email, $user_id, $product_id );
	}

	/**
	 * Render the "Buy this reading" gate HTML.
	 *
	 * @since 1.2.6
	 * @param int $reading_id Reading post ID, used for context messaging.
	 * @param int $product_id WooCommerce product post ID.
	 * @return string Gate HTML, or empty string when WC isn't active or product is missing.
	 */
	public static function render_purchase_gate( $reading_id, $product_id ) {
		if ( ! self::is_active() || $product_id <= 0 ) {
			return '';
		}
		if ( ! function_exists( 'wc_get_product' ) ) {
			return '';
		}

		$product = wc_get_product( $product_id );
		if ( ! $product ) {
			return '';
		}

		$reading_title = function_exists( 'get_the_title' ) ? get_the_title( $reading_id ) : '';
		$price_html    = method_exists( $product, 'get_price_html' ) ? $product->get_price_html() : '';
		$permalink     = method_exists( $product, 'get_permalink' ) ? $product->get_permalink() : '';
		$add_to_cart   = method_exists( $product, 'add_to_cart_url' ) ? $product->add_to_cart_url() : $permalink;

		ob_start();
		?>
		<div class="card-oracle-wc-gate" data-reading-id="<?php echo esc_attr( $reading_id ); ?>" data-product-id="<?php echo esc_attr( $product_id ); ?>">
			<h3 class="card-oracle-wc-gate__heading">
				<?php
				printf(
					/* translators: %s: reading title */
					esc_html__( 'Unlock %s', 'card-oracle' ),
					esc_html( $reading_title )
				);
				?>
			</h3>
			<?php if ( '' !== $price_html ) : ?>
				<p class="card-oracle-wc-gate__price"><?php echo wp_kses_post( $price_html ); ?></p>
			<?php endif; ?>
			<p class="card-oracle-wc-gate__cta">
				<a class="button card-oracle-wc-gate__button" href="<?php echo esc_url( $add_to_cart ); ?>">
					<?php esc_html_e( 'Buy this reading', 'card-oracle' ); ?>
				</a>
				<?php if ( '' !== $permalink && $permalink !== $add_to_cart ) : ?>
					<a class="card-oracle-wc-gate__details" href="<?php echo esc_url( $permalink ); ?>">
						<?php esc_html_e( 'Details', 'card-oracle' ); ?>
					</a>
				<?php endif; ?>
			</p>
			<p class="card-oracle-wc-gate__hint description">
				<?php esc_html_e( 'After your order is complete, return to this page and your reading will be unlocked.', 'card-oracle' ); ?>
			</p>
		</div>
		<?php
		return (string) ob_get_clean();
	}

	/**
	 * Decide whether a reading should be gated for the current visitor.
	 *
	 * Returns the gate HTML when access should be blocked, or an empty string
	 * when the visitor can proceed (no link, WC inactive, or already purchased).
	 *
	 * @since 1.2.6
	 * @param int $reading_id Reading post ID.
	 * @return string
	 */
	public static function maybe_render_gate( $reading_id ) {
		if ( ! self::is_active() ) {
			return '';
		}

		$product_id = self::get_linked_product_id( $reading_id );
		if ( $product_id <= 0 ) {
			return '';
		}

		if ( self::customer_has_purchased( $product_id ) ) {
			return '';
		}

		return self::render_purchase_gate( $reading_id, $product_id );
	}

	/**
	 * Build a list of published WooCommerce products keyed by ID.
	 *
	 * Used by the admin reading metabox dropdown.
	 *
	 * @since 1.2.6
	 * @return array<int|string, string>
	 */
	public static function get_products_for_select() {
		$options = array( '' => __( '— No WooCommerce product —', 'card-oracle' ) );

		if ( ! self::is_active() || ! function_exists( 'get_posts' ) ) {
			return $options;
		}

		$products = get_posts(
			array(
				'post_type'      => 'product',
				'post_status'    => 'publish',
				'posts_per_page' => 200, // phpcs:ignore WordPress.WP.PostsPerPage.posts_per_page_posts_per_page -- admin select.
				'orderby'        => 'title',
				'order'          => 'ASC',
				'fields'         => 'ids',
				'no_found_rows'  => true,
			)
		);

		if ( ! empty( $products ) && function_exists( 'get_the_title' ) ) {
			foreach ( $products as $product_id ) {
				$options[ (string) $product_id ] = get_the_title( $product_id );
			}
		}

		return $options;
	}
}
