<?php
/**
 * Shared base class for cart recovery emails.
 *
 * @package EDD\Pro\CartRecovery\Emails\Types
 * @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\Types;

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

use EDD\Emails\Types\Email;
use EDD\Pro\CartRecovery\Config\Emails;

/**
 * Shared base class for ACR recovery emails.
 */
abstract class Base extends Email {

	/**
	 * Email context for template helpers.
	 *
	 * @var string
	 */
	protected $context = 'abandoned_cart';

	/**
	 * Recipient type used for logging.
	 *
	 * @var string
	 */
	protected $recipient_type = 'customer';

	/**
	 * Recovery cart payload.
	 *
	 * @var object
	 */
	protected $cart;

	/**
	 * Recovery token metadata.
	 *
	 * @var array
	 */
	protected $token_data = array();

	/**
	 * Data passed into template filters.
	 *
	 * @var array
	 */
	protected $email_data = array();

	/**
	 * Whether send() should be aborted due to missing data.
	 *
	 * @var bool
	 */
	protected $abort_send = false;

	/**
	 * Constructor.
	 *
	 * @param object $cart       Cart payload (stdClass or RecoveryCart row).
	 * @param array  $token_data Recovery token metadata.
	 */
	public function __construct( object $cart, array $token_data = array() ) {
		$this->cart       = $cart;
		$this->token_data = $token_data;

		$cart_id = isset( $cart->id ) ? (int) $cart->id : 0;

		$this->email_data = array(
			'cart_id' => $cart_id,
			'cart'    => $cart,
			'token'   => $token_data,
		);
	}

	/**
	 * Gets the recovery token.
	 *
	 * @since 3.6.5
	 * @return string Recovery token.
	 */
	public function get_token(): string {
		if ( isset( $this->token_data['token'] ) ) {
			return (string) $this->token_data['token'];
		}

		if ( isset( $this->token_data[0] ) && ! is_array( $this->token_data[0] ) ) {
			return (string) $this->token_data[0];
		}

		return '';
	}

	/**
	 * Gets the cart.
	 *
	 * @since 3.6.5
	 * @return object Cart object.
	 */
	public function get_cart(): object {
		return $this->cart;
	}

	/**
	 * Sets the to email.
	 *
	 * @since 3.6.5
	 * @return void
	 */
	protected function set_to_email() {
		$this->send_to = $this->resolve_recipient( $this->email_data );
	}

	/**
	 * Sets the from name.
	 *
	 * @since 3.6.5
	 * @return void
	 */
	protected function set_from_name() {
		$this->from_name = Emails::get_sender_name();
	}

	/**
	 * Sets the from email.
	 *
	 * @since 3.6.5
	 * @return void
	 */
	protected function set_from_email() {
		$this->from_email = Emails::get_sender_email();
	}

	/**
	 * Sets the email subject with template tags processed.
	 *
	 * @since 3.6.5
	 * @return void
	 */
	protected function set_subject() {
		$this->subject = $this->process_tags(
			$this->get_email()->subject,
			$this->email_data['cart_id'],
			$this->email_data['cart'],
			$this
		);
	}

	/**
	 * Set the email message.
	 *
	 * @since 3.6.5
	 * @return void
	 */
	protected function set_message() {
		parent::set_message();

		$this->message = $this->process_tags( $this->message, $this->email_data['cart_id'], $this->email_data['cart'], $this );
	}

	/**
	 * Checks if the email should be sent.
	 *
	 * @since 3.6.5
	 * @return bool Whether the email should be sent.
	 */
	protected function should_send() {
		if ( ! parent::should_send() ) {
			return false;
		}

		if ( empty( $this->get_token() ) ) {
			return false;
		}

		if ( $this->abort_send ) {
			return false;
		}

		$expires_at = $this->get_expiration_timestamp();
		if ( null !== $expires_at && time() > $expires_at ) {
			return false;
		}

		return true;
	}

	/**
	 * Determines the intended recipient address for the provided template data.
	 *
	 * @since 3.6.5
	 * @param array $email Email payload passed through the pipeline.
	 */
	private function resolve_recipient( array $email ): string {
		$address = '';
		if ( isset( $email['recipient'] ) && is_string( $email['recipient'] ) ) {
			$address = sanitize_email( $email['recipient'] );
		}

		if ( '' !== $address ) {
			return $address;
		}

		$cart_id = isset( $email['cart_id'] ) ? (int) $email['cart_id'] : 0;
		if ( $cart_id <= 0 ) {
			return '';
		}

		$cart_repo = new \EDD\Pro\CartRecovery\Database\Queries\RecoveryCart();
		$cart      = $cart_repo->get_item( $cart_id );

		return $cart && ! empty( $cart->email ) ? sanitize_email( (string) $cart->email ) : '';
	}

	/**
	 * Gets the expiration timestamp.
	 *
	 * @since 3.6.5
	 * @return int|null Expiration timestamp.
	 */
	private function get_expiration_timestamp(): ?int {
		if ( empty( $this->token_data['expires_at'] ) ) {
			return null;
		}

		$expires_at = $this->token_data['expires_at'];

		if ( is_numeric( $expires_at ) ) {
			return (int) $expires_at;
		}

		$timestamp = strtotime( (string) $expires_at );

		return false === $timestamp ? null : $timestamp;
	}

	/**
	 * Checks if the email should be aborted.
	 *
	 * @since 3.6.5
	 * @return bool Whether the email should be aborted.
	 */
	public function did_abort_send(): bool {
		return (bool) $this->abort_send;
	}
}
