<?php
/**
 * Review Request Email Scheduler.
 *
 * Hooks into WooCommerce order completion and WordPress user registration to
 * schedule delayed "please leave a review" emails via WP-Cron.
 *
 * Deduplication is handled through WooCommerce order meta and WordPress user
 * meta so that each recipient is sent at most one review-request email per
 * trigger event.
 *
 * @package Ugcify\Email
 */

namespace Ugcify\Email;

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

/**
 * Class ReviewRequestScheduler
 */
class ReviewRequestScheduler {

	/**
	 * WP-Cron hook for order-based review request sends.
	 *
	 * @var string
	 */
	const CRON_ORDER_HOOK = 'ugcify_review_request_order';

	/**
	 * WP-Cron hook for user-registration-based review request sends.
	 *
	 * @var string
	 */
	const CRON_USER_HOOK = 'ugcify_review_request_user';

	/**
	 * WooCommerce order meta key used to flag that the email was sent.
	 *
	 * @var string
	 */
	const ORDER_META_SENT = '_ugcify_rreq_sent';

	/**
	 * WordPress user meta key used to flag that the registration email was sent.
	 *
	 * @var string
	 */
	const USER_META_SENT = '_ugcify_rreq_reg_sent';

	/**
	 * Register all hooks.
	 */
	public function __construct() {
		// Always register cron handlers so scheduled events can fire even if
		// WooCommerce is temporarily unavailable.
		add_action( self::CRON_ORDER_HOOK, array( $this, 'send_for_order' ), 10, 1 );
		add_action( self::CRON_USER_HOOK, array( $this, 'send_for_user' ), 10, 1 );

		// Schedule on WooCommerce order completion.
		if ( class_exists( 'WooCommerce' ) ) {
			add_action( 'woocommerce_order_status_completed', array( $this, 'schedule_for_order' ), 10, 1 );
		}

		// Schedule on WordPress user registration.
		add_action( 'user_register', array( $this, 'schedule_for_user' ), 10, 1 );
	}

	// =========================================================================
	// Scheduling
	// =========================================================================

	/**
	 * Schedule a review request email for a completed WooCommerce order.
	 *
	 * @param int $order_id WooCommerce order ID.
	 * @return void
	 */
	public function schedule_for_order( $order_id ) {
		$settings = ReviewRequestSettings::get();

		if ( ! in_array( 'woo_customers', $settings['audience'], true ) ) {
			return;
		}

		if ( ! EmailSettings::is_enabled( 'review_request' ) ) {
			return;
		}

		$delay     = absint( $settings['delay_days'] ) * DAY_IN_SECONDS;
		$timestamp = time() + $delay;

		if ( ! wp_next_scheduled( self::CRON_ORDER_HOOK, array( $order_id ) ) ) {
			wp_schedule_single_event( $timestamp, self::CRON_ORDER_HOOK, array( $order_id ) );
		}
	}

	/**
	 * Schedule a review request email for a newly registered WordPress user.
	 *
	 * @param int $user_id WordPress user ID.
	 * @return void
	 */
	public function schedule_for_user( $user_id ) {
		$settings = ReviewRequestSettings::get();

		if ( ! in_array( 'wp_users', $settings['audience'], true ) ) {
			return;
		}

		if ( ! EmailSettings::is_enabled( 'review_request' ) ) {
			return;
		}

		$delay     = absint( $settings['delay_days'] ) * DAY_IN_SECONDS;
		$timestamp = time() + $delay;

		if ( ! wp_next_scheduled( self::CRON_USER_HOOK, array( $user_id ) ) ) {
			wp_schedule_single_event( $timestamp, self::CRON_USER_HOOK, array( $user_id ) );
		}
	}

	// =========================================================================
	// Sending
	// =========================================================================

	/**
	 * Send a review request email for a WooCommerce order (called by WP-Cron).
	 *
	 * @param int $order_id WooCommerce order ID.
	 * @return void
	 */
	public function send_for_order( $order_id ) {
		// Re-check settings at send time in case they changed since scheduling.
		$settings = ReviewRequestSettings::get();

		if ( ! in_array( 'woo_customers', $settings['audience'], true ) ) {
			return;
		}

		if ( ! EmailSettings::is_enabled( 'review_request' ) ) {
			return;
		}

		if ( ! class_exists( 'WooCommerce' ) ) {
			return;
		}

		$order = wc_get_order( $order_id );
		if ( ! $order ) {
			return;
		}

		// Guard against duplicate sends.
		if ( $order->get_meta( self::ORDER_META_SENT ) === '1' ) {
			return;
		}

		$recipient_email = $order->get_billing_email();
		if ( empty( $recipient_email ) || ! is_email( $recipient_email ) ) {
			return;
		}

		// Skip if the user already reviewed the ordered products.
		if ( $settings['exclude_reviewed'] && $this->user_has_reviewed_order_products( $order ) ) {
			return;
		}

		$data = $this->build_order_placeholder_data( $order );
		$sent = EmailSender::send( 'review_request', $recipient_email, $data );

		if ( $sent ) {
			$order->update_meta_data( self::ORDER_META_SENT, '1' );
			$order->save_meta_data();
		}
	}

	/**
	 * Send a review request email for a registered WP user (called by WP-Cron).
	 *
	 * @param int $user_id WordPress user ID.
	 * @return void
	 */
	public function send_for_user( $user_id ) {
		$settings = ReviewRequestSettings::get();

		if ( ! in_array( 'wp_users', $settings['audience'], true ) ) {
			return;
		}

		if ( ! EmailSettings::is_enabled( 'review_request' ) ) {
			return;
		}

		$user = get_user_by( 'id', $user_id );
		if ( ! $user ) {
			return;
		}

		// Guard against duplicate sends.
		if ( get_user_meta( $user_id, self::USER_META_SENT, true ) ) {
			return;
		}

		$shop_url   = ( class_exists( 'WooCommerce' ) && function_exists( 'wc_get_page_id' ) )
			? get_permalink( wc_get_page_id( 'shop' ) )
			: '';
		$review_url = $shop_url ?: home_url();

		$data = array(
			'user_name'    => $user->display_name,
			'user_email'   => $user->user_email,
			'site_name'    => get_bloginfo( 'name' ),
			'order_id'     => '',
			'product_name' => get_bloginfo( 'name' ),
			'product_link' => '<a href="' . esc_url( $review_url ) . '">' . esc_html( get_bloginfo( 'name' ) ) . '</a>',
			'review_url'   => $review_url,
		);

		$sent = EmailSender::send( 'review_request', $user->user_email, $data );

		if ( $sent ) {
			update_user_meta( $user_id, self::USER_META_SENT, current_time( 'mysql' ) );
		}
	}

	// =========================================================================
	// Helpers
	// =========================================================================

	/**
	 * Check whether the order's customer has already reviewed any of the ordered products.
	 *
	 * @param \WC_Order $order WooCommerce order object.
	 * @return bool
	 */
	private function user_has_reviewed_order_products( $order ) {
		$user_id = (int) $order->get_customer_id();
		if ( $user_id <= 0 ) {
			return false;
		}

		global $wpdb;

		foreach ( $order->get_items() as $item ) {
			$product = $item->get_product();
			if ( ! $product ) {
				continue;
			}

			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
			$count = (int) $wpdb->get_var(
				$wpdb->prepare(
					"SELECT COUNT(*) FROM {$wpdb->comments}
					 WHERE comment_post_ID = %d
					   AND user_id = %d
					   AND comment_type = 'review'
					   AND comment_approved = '1'",
					$product->get_id(),
					$user_id
				)
			);

			if ( $count > 0 ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Build placeholder data from a WooCommerce order.
	 *
	 * @param \WC_Order $order WooCommerce order object.
	 * @return array
	 */
	private function build_order_placeholder_data( $order ) {
		$first_name = $order->get_billing_first_name();
		$last_name  = $order->get_billing_last_name();
		$user_name  = trim( $first_name . ' ' . $last_name );

		// Prefer the display name if the customer has a WP account.
		$user_id = (int) $order->get_customer_id();
		if ( $user_id > 0 ) {
			$user = get_user_by( 'id', $user_id );
			if ( $user ) {
				$user_name = $user->display_name;
			}
		}

		$product_names = array();
		$product_links = array();
		$review_urls   = array();

		foreach ( $order->get_items() as $item ) {
			$product_names[] = $item->get_name();
			$product = $item->get_product();
			if ( $product ) {
				$url = get_permalink( $product->get_id() );
				if ( $url ) {
					$review_urls[]   = $url;
					$product_links[] = '<a href="' . esc_url( $url ) . '">' . esc_html( $item->get_name() ) . '</a>';
				} else {
					$product_links[] = esc_html( $item->get_name() );
				}
			} else {
				$product_links[] = esc_html( $item->get_name() );
			}
		}

		return array(
			'user_name'    => $user_name ?: __( 'Customer', 'ugcify' ),
			'user_email'   => $order->get_billing_email(),
			'site_name'    => get_bloginfo( 'name' ),
			'order_id'     => $order->get_id(),
			'product_name' => implode( ', ', $product_names ),
			'product_link' => implode( ', ', $product_links ),
			'review_url'   => $review_urls ? $review_urls[0] : home_url(),
		);
	}
}
