<?php
/**
 * Class WC_Payments_Post_Kyc_Activation_Email_Service
 *
 * @package WooCommerce\Payments
 */

defined( 'ABSPATH' ) || exit;

/**
 * Schedules and sends post-KYC activation emails on day 7, 14, and 30 to merchants
 * who have not yet made their first live WooPayments sale.
 *
 * Three one-off Action Scheduler actions are scheduled per store the first time the
 * KYC completion date is recorded — calculated as kyc_date + 7d / +14d / +30d. Each
 * action handler re-checks eligibility at fire time and bails if the merchant has
 * since made a sale, gone back to test mode, etc.
 */
class WC_Payments_Post_Kyc_Activation_Email_Service {

	const SEND_HOOK = 'wcpay_post_kyc_activation_email_send';

	const EMAIL_SENT_OPTION = 'wcpay_post_kyc_activation_email_sent_stages';

	const SCHEDULED_OPTION = 'wcpay_post_kyc_activation_emails_scheduled';

	const STAGE_DAYS = [ 7, 14, 30 ];

	/**
	 * Stages whose calculated send time is more than this far in the past are skipped at scheduling time
	 * — avoids spamming long-since-approved merchants with stale activation nudges.
	 */
	const STALE_GRACE_SECONDS = 7 * DAY_IN_SECONDS;

	/**
	 * Account service instance.
	 *
	 * @var WC_Payments_Account
	 */
	private $account;

	/**
	 * WCPay gateway instance.
	 *
	 * @var WC_Payment_Gateway_WCPay
	 */
	private $wcpay_gateway;

	/**
	 * Order service instance.
	 *
	 * @var WC_Payments_Order_Service
	 */
	private $order_service;

	/**
	 * Constructor.
	 *
	 * @param WC_Payments_Account       $account       Account service.
	 * @param WC_Payment_Gateway_WCPay  $wcpay_gateway WCPay gateway.
	 * @param WC_Payments_Order_Service $order_service Order service.
	 */
	public function __construct( WC_Payments_Account $account, WC_Payment_Gateway_WCPay $wcpay_gateway, WC_Payments_Order_Service $order_service ) {
		$this->account       = $account;
		$this->wcpay_gateway = $wcpay_gateway;
		$this->order_service = $order_service;
	}

	/**
	 * Register hooks.
	 *
	 * @return void
	 */
	public function init_hooks(): void {
		// Schedule the three one-off send actions the first time KYC completion is recorded.
		add_action( 'add_option_' . WC_Payments_Account::KYC_COMPLETION_DATE_OPTION, [ $this, 'schedule_stage_emails' ], 10, 2 );
		// Handler for each scheduled stage send.
		add_action( self::SEND_HOOK, [ $this, 'send_email_for_stage' ] );
		// Tracks click-throughs from the email CTA into the Marketing Hub.
		add_action( 'admin_init', [ $this, 'maybe_track_cta_click' ] );
	}

	/**
	 * Schedule day-7, day-14, and day-30 send actions when the KYC completion date is first recorded.
	 * Stages whose calculated send time is more than STALE_GRACE_SECONDS in the past are skipped.
	 *
	 * @param string $option_name The option name fired by the add_option_* action.
	 * @param mixed  $value       The option value.
	 * @return void
	 */
	public function schedule_stage_emails( $option_name, $value ): void {
		if ( ! function_exists( 'as_schedule_single_action' ) ) {
			return;
		}

		if ( get_option( self::SCHEDULED_OPTION ) ) {
			return;
		}

		$kyc_date = (int) $value;
		if ( ! $kyc_date ) {
			return;
		}

		$now = time();
		foreach ( self::STAGE_DAYS as $stage ) {
			$send_at = $kyc_date + $stage * DAY_IN_SECONDS;

			if ( $send_at < $now - self::STALE_GRACE_SECONDS ) {
				continue;
			}

			as_schedule_single_action( max( $send_at, $now + 60 ), self::SEND_HOOK, [ $stage ], 'woocommerce-payments' );
		}

		update_option( self::SCHEDULED_OPTION, '1', false );
	}

	/**
	 * Action Scheduler handler — fires once per stage at the scheduled time.
	 *
	 * @param int $stage The stage day (7, 14, or 30).
	 * @return void
	 */
	public function send_email_for_stage( $stage ): void {
		$stage = (int) $stage;

		if ( ! in_array( $stage, self::STAGE_DAYS, true ) ) {
			return;
		}

		$sent_stages = (array) get_option( self::EMAIL_SENT_OPTION, [] );
		if ( in_array( $stage, $sent_stages, true ) ) {
			return;
		}

		// Re-check staleness at fire time in case Action Scheduler runs the
		// action well after its scheduled time (e.g. WP-Cron stalled for weeks).
		$kyc_date = (int) get_option( WC_Payments_Account::KYC_COMPLETION_DATE_OPTION, 0 );
		if ( ! $kyc_date ) {
			return;
		}
		if ( time() > $kyc_date + $stage * DAY_IN_SECONDS + self::STALE_GRACE_SECONDS ) {
			return;
		}

		if ( ! $this->is_eligible() ) {
			return;
		}

		if ( ! function_exists( 'WC' ) || ! WC()->mailer() ) {
			return;
		}

		$emails = WC()->mailer()->get_emails();
		$email  = $emails['WC_Payments_Email_Post_Kyc_Activation'] ?? null;

		if ( ! $email instanceof WC_Payments_Email_Post_Kyc_Activation ) {
			return;
		}

		// Merchant opted out — email disabled in WC > Settings > Emails, or
		// no recipient. Nothing to send; let the stage expire silently.
		if ( ! $email->is_enabled() || ! $email->get_recipient() ) {
			return;
		}

		if ( ! $email->trigger( $stage ) ) {
			// Mailer rejected the send (e.g. SMTP failure). Leave the stage
			// unconsumed so the drop surfaces via the
			// `wcpay_post_kyc_activation_email_send_failed` tracks event
			// rather than being silently swallowed.
			return;
		}

		$sent_stages[] = $stage;
		update_option( self::EMAIL_SENT_OPTION, array_values( array_unique( $sent_stages ) ), false );
	}

	/**
	 * Eligibility check — mirrors the in-app banner logic.
	 *
	 * @return bool
	 */
	public function is_eligible(): bool {
		if ( ! $this->wcpay_gateway->is_connected() || ! $this->account->is_stripe_account_valid() ) {
			return false;
		}

		$account_status = $this->account->get_account_status_data();

		if ( ! empty( $account_status['testDrive'] ) ) {
			return false;
		}

		if ( empty( $account_status['paymentsEnabled'] ) ) {
			return false;
		}

		if ( WC_Payments::mode()->is_test() || WC_Payments::mode()->is_dev() ) {
			return false;
		}

		if ( ! get_option( WC_Payments_Account::KYC_COMPLETION_DATE_OPTION ) ) {
			return false;
		}

		return ! $this->order_service->has_live_sale();
	}

	/**
	 * Fires `wcpay_post_kyc_activation_email_cta_clicked` when an admin lands on
	 * Marketing Hub via the email CTA, then strips the marker query args so a
	 * page refresh doesn't double-count the click.
	 *
	 * @return void
	 */
	public function maybe_track_cta_click(): void {
		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		if ( ! isset( $_GET['wcpay_referrer'] ) || 'post_kyc_email' !== $_GET['wcpay_referrer'] ) {
			return;
		}

		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			return;
		}

		$stage = isset( $_GET['wcpay_referrer_stage'] ) ? (int) $_GET['wcpay_referrer_stage'] : 0;
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		if ( ! in_array( $stage, self::STAGE_DAYS, true ) ) {
			return;
		}

		if ( class_exists( 'WC_Tracks' ) ) {
			WC_Tracks::record_event( 'wcpay_post_kyc_activation_email_cta_clicked', [ 'stage' => $stage ] );
		}

		wp_safe_redirect( remove_query_arg( [ 'wcpay_referrer', 'wcpay_referrer_stage' ] ) );
		exit;
	}
}