<?php
/**
 * Handles email bounce events.
 *
 * @package EDD\Pro\CartRecovery\Emails
 * @copyright Copyright (c) 2026, Sandhills Development, LLC
 * @license https://opensource.org/licenses/GPL-2.0 GNU Public License
 * @since 3.6.5
 */

namespace EDD\Pro\CartRecovery\Emails;

// Exit if accessed directly.
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore

use EDD\EventManagement\SubscriberInterface;
use EDD\Pro\CartRecovery\Database\Queries\RecoveryEmail as EmailQuery;
use EDD\Pro\CartRecovery\Journey\EventLogger;

/**
 * Handles email bounce events.
 *
 * @since 3.6.5
 */
class Bounce implements SubscriberInterface {

	/**
	 * Gets the subscribed events.
	 *
	 * @since 3.6.5
	 * @return array
	 */
	public static function get_subscribed_events(): array {
		return array(
			'edd_email_bounced' => array( 'handle_email_bounced', 10, 2 ),
		);
	}

	/**
	 * Handles a bounce recorded on a core email log entry.
	 *
	 * Bridges the core bounce webhook to ACR by finding the matching
	 * recovery email and recording the bounce on it.
	 *
	 * @since 3.6.5
	 * @param int    $email_log_id The email log ID (from edd_logs_emails).
	 * @param string $reason       The bounce reason.
	 */
	public function handle_email_bounced( int $email_log_id, string $reason ): void {
		$log_query = new \EDD\Database\Queries\LogEmail();
		$email_log = $log_query->get_item( $email_log_id );

		if ( ! $email_log || empty( $email_log->email ) ) {
			return;
		}

		$email_hash  = hash( 'sha256', strtolower( $email_log->email ) );
		$email_query = new EmailQuery();
		$acr_emails  = $email_query->query(
			array(
				'email_hash' => $email_hash,
				'orderby'    => 'date_sent',
				'order'      => 'DESC',
				'number'     => 1,
			)
		);

		if ( empty( $acr_emails ) ) {
			return;
		}

		$this->record_bounce( (int) $acr_emails[0]->id, $reason );
	}

	/**
	 * Records an email bounce event.
	 *
	 * @since 3.6.5
	 * @param int    $email_id     The recovery email ID.
	 * @param string $bounce_reason The reason for the bounce.
	 * @return bool True if recorded, false on error.
	 */
	private function record_bounce( int $email_id, string $bounce_reason ): bool {
		if ( $email_id <= 0 ) {
			return false;
		}

		$email_query = new EmailQuery();
		$email       = $email_query->get_item( $email_id );

		if ( ! $email ) {
			edd_debug_log( sprintf( '[EDD ACR Tracking] Cannot record bounce: email %d not found', $email_id ) );
			return false;
		}

		$updated = $email_query->update_item(
			$email_id,
			array(
				'bounce_reason'   => sanitize_text_field( $bounce_reason ),
				'delivery_status' => 'bounced',
			)
		);

		if ( $updated ) {
			edd_debug_log( sprintf( '[EDD ACR Tracking] Email %d bounced: %s', $email_id, $bounce_reason ) );

			// Log email_bounced journey event.
			if ( ! empty( $email->cart_id ) ) {
				$event_logger = new EventLogger();
				$event_logger->log_email_event(
					'email_bounced',
					(int) $email->cart_id,
					$email_id,
					array( 'bounce_reason' => $bounce_reason )
				);
			}
		} else {
			edd_debug_log( sprintf( '[EDD ACR Tracking] Failed to record bounce for email %d', $email_id ), true );
		}

		return (bool) $updated;
	}
}
