<?php
/**
 * Notification handler.
 *
 * Sends back-in-stock emails, admin alerts, and logs notifications.
 *
 * @package Waitlytics
 */

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

/**
 * Class WTLY_Notification
 */
class WTLY_Notification {

	/**
	 * Batch size for notification sending.
	 *
	 * @var int
	 */
	const BATCH_SIZE = 20;

	/**
	 * Send back-in-stock notifications for a product.
	 *
	 * Sends in batches to avoid timeouts. Remaining subscribers
	 * are processed via a scheduled single cron event.
	 *
	 * @param int $product_id   Product ID.
	 * @param int $variation_id Optional. Variation ID. Default 0.
	 * @return int Number of emails sent in this batch.
	 */
	public function send_back_in_stock_notifications( $product_id, $variation_id = 0 ) {
		$product_id   = absint( $product_id );
		$variation_id = absint( $variation_id );

		$subscriber  = new WTLY_Subscriber();
		$subscribers = $subscriber->get_active_by_product( $product_id, $variation_id );

		if ( empty( $subscribers ) ) {
			return 0;
		}

		$target_id = $variation_id > 0 ? $variation_id : $product_id;
		$product   = wc_get_product( $target_id );
		if ( ! $product || ! $product->is_in_stock() ) {
			return 0;
		}

		$settings   = wtly_get_settings();
		$sent_count = 0;
		$batch      = array_slice( $subscribers, 0, self::BATCH_SIZE );

		foreach ( $batch as $sub ) {
			$sent = $this->send_single_notification( $sub, $product, $settings );
			if ( $sent ) {
				$subscriber->update_status( $sub->id, 'notified' );
				$this->log_notification( $sub->id, $product_id, $variation_id, $sub->email );
				$sent_count++;
			}
		}

		// Schedule remaining subscribers for next batch.
		if ( count( $subscribers ) > self::BATCH_SIZE ) {
			wp_schedule_single_event(
				time() + 60,
				'wtly_send_notification_batch',
				array( $product_id, $variation_id, self::BATCH_SIZE )
			);
		}

		/**
		 * Fires after a batch of notifications is sent.
		 *
		 * @param int $product_id Product ID.
		 * @param int $sent_count Number of emails sent.
		 */
		do_action( 'wtly_after_notifications_sent', $product_id, $sent_count );

		return $sent_count;
	}

	/**
	 * Send a single back-in-stock notification email.
	 *
	 * @param object     $subscriber Subscriber row from database.
	 * @param WC_Product $product    WooCommerce product object.
	 * @param array      $settings   Plugin settings.
	 * @return bool Whether the email was sent successfully.
	 */
	public function send_single_notification( $subscriber, $product, $settings ) {
		$email_templates = new WTLY_Email_Templates();
		$html            = $email_templates->render_back_in_stock_email( $subscriber, $product, $settings );

		if ( empty( $html ) ) {
			return false;
		}

		$product_name = $product->get_name();
		$subject      = $this->get_email_subject( $product_name, $settings );
		$from_name    = ! empty( $settings['email_from_name'] ) ? $settings['email_from_name'] : get_bloginfo( 'name' );
		$from_email   = ! empty( $settings['email_from_address'] ) ? $settings['email_from_address'] : get_option( 'admin_email' );

		$headers = array(
			'Content-Type: text/html; charset=UTF-8',
			sprintf( 'From: %s <%s>', sanitize_text_field( $from_name ), sanitize_email( $from_email ) ),
		);

		$sent = wp_mail( $subscriber->email, $subject, $html, $headers );

		return $sent;
	}

	/**
	 * Log a sent notification to the notifications log table.
	 *
	 * @param int    $subscriber_id Subscriber ID.
	 * @param int    $product_id    Product ID.
	 * @param int    $variation_id  Variation ID.
	 * @param string $email         Subscriber email.
	 */
	public function log_notification( $subscriber_id, $product_id, $variation_id, $email ) {
		global $wpdb;

		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$wpdb->insert(
			$wpdb->prefix . 'wtly_notifications_log',
			array(
				'subscriber_id' => absint( $subscriber_id ),
				'product_id'    => absint( $product_id ),
				'variation_id'  => absint( $variation_id ),
				'email'         => sanitize_email( $email ),
			),
			array( '%d', '%d', '%d', '%s' )
		);
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
	}

	/**
	 * Send admin email about a new subscriber.
	 *
	 * @param array $subscriber_data {
	 *     @type string $email      Subscriber email.
	 *     @type int    $product_id Product ID.
	 * }
	 */
	public function send_admin_new_subscriber_email( $subscriber_data ) {
		$settings = wtly_get_settings();

		if ( empty( $settings['admin_notify_new_subscriber'] ) ) {
			return;
		}

		$admin_email = ! empty( $settings['admin_notify_email'] )
			? $settings['admin_notify_email']
			: get_option( 'admin_email' );

		$product      = wc_get_product( absint( $subscriber_data['product_id'] ) );
		$product_name = $product ? $product->get_name() : __( '(Unknown product)', 'waitlytics' );

		$subject = sprintf(
			/* translators: %s: site name */
			__( '[%s] New Back-in-Stock Subscriber', 'waitlytics' ),
			get_bloginfo( 'name' )
		);

		$message = sprintf(
			/* translators: 1: email address, 2: product name */
			__( 'A new subscriber has signed up for back-in-stock notifications.

Email: %1$s
Product: %2$s

Manage subscribers in your WordPress admin under WooCommerce → Waitlytics.', 'waitlytics' ),
			sanitize_email( $subscriber_data['email'] ),
			$product_name
		);

		$headers = array( 'Content-Type: text/plain; charset=UTF-8' );

		wp_mail( sanitize_email( $admin_email ), $subject, $message, $headers );
	}

	/**
	 * Send admin low stock alert email.
	 *
	 * @param int $product_id    Product ID.
	 * @param int $current_stock Current stock quantity.
	 */
	public function send_admin_low_stock_email( $product_id, $current_stock ) {
		$settings = wtly_get_settings();

		if ( empty( $settings['admin_low_stock_email'] ) ) {
			return;
		}

		$admin_email = ! empty( $settings['admin_notify_email'] )
			? $settings['admin_notify_email']
			: get_option( 'admin_email' );

		$product      = wc_get_product( absint( $product_id ) );
		$product_name = $product ? $product->get_name() : __( '(Unknown product)', 'waitlytics' );

		$subscriber  = new WTLY_Subscriber();
		$sub_count   = $subscriber->count_by_product( $product_id );

		$subject = sprintf(
			/* translators: %s: site name */
			__( '[%s] Low Stock Alert', 'waitlytics' ),
			get_bloginfo( 'name' )
		);

		$message = sprintf(
			/* translators: 1: product name, 2: current stock, 3: subscriber count */
			__( 'Low stock alert for your WooCommerce store.

Product: %1$s
Current Stock: %2$d
Waitlist Subscribers: %3$d

Consider restocking this item soon.', 'waitlytics' ),
			$product_name,
			absint( $current_stock ),
			$sub_count
		);

		$headers = array( 'Content-Type: text/plain; charset=UTF-8' );

		wp_mail( sanitize_email( $admin_email ), $subject, $message, $headers );
	}

	/**
	 * Generate an unsubscribe URL for a subscriber.
	 *
	 * @param object $subscriber Subscriber row from database.
	 * @return string Unsubscribe URL.
	 */
	public function get_unsubscribe_url( $subscriber ) {
		$token = wp_hash( $subscriber->id . $subscriber->email . $subscriber->product_id );

		return add_query_arg(
			array(
				'wtly_unsubscribe' => '1',
				'sub_id'           => absint( $subscriber->id ),
				'token'            => $token,
			),
			home_url()
		);
	}

	/**
	 * Get email subject line with placeholder replacement.
	 *
	 * @param string $product_name Product name.
	 * @param array  $settings     Plugin settings.
	 * @return string Email subject.
	 */
	private function get_email_subject( $product_name, $settings ) {
		$subject = ! empty( $settings['email_subject'] )
			? $settings['email_subject']
			: '{product_name} ' . __( 'is back in stock!', 'waitlytics' );

		return str_replace( '{product_name}', $product_name, $subject );
	}
}
