<?php
/**
 * A class to send the (new) order email.
 *
 * @since 3.0.0
 */

declare( strict_types=1 );
namespace FeData\FastEvents\Hooks\Actions;

defined( 'ABSPATH' ) || exit;

use Exception;
use FeData\FastEvents\Logging\LoggerFactory;
use FeData\FastEvents\Mail\MailerFactory;
use FeData\FastEvents\Mail\MailerInterface;
use FeData\FastEvents\Storage\Options;
use FeData\FastEvents\Utilities\JsonUtil;

/**
 * A class to A class to send the (new) order email.
 */
final class SendMailAction {

	/**
	 * SendMailAction constructor.
	 *
	 * @since 3.0.0
	 *
	 * @param LoggerFactory $logger  Logger class.
	 * @param Options       $options Options class.
	 * @param MailerFactory $mailer  Mailer class.
	 */
	public function __construct(
		private readonly LoggerFactory $logger,
		private readonly Options $options,
		private readonly MailerFactory $mailer
	) {}


	/**
	 * Action to send the (new) order email.
	 * If we end here, it is the result of a previous email failure and retries are enabled in the plugin settings.
	 *
	 * @since 1.0
	 * @since 1.4 Added sender_name and sender_email to query
	 * @since 1.9 New logging and added event_id to scheduler
	 * @since 2.0.3 Using the new format from the options table
	 * @since 2.1.0 Added redirect to query
	 * @since 2.3.0 Use fast_events_json_encode.
	 *
	 * @param int    $order_id        Order identifier.
	 * @param int    $event_id        Event identifier.
	 * @param string $to              Emailaddress of the recipient.
	 * @param int    $em_type         0=Normal mail, 1=Confirmation email, >100=Message saved on disk.
	 * @param string $created         Entry creation date (YYYY-MM-DD HH:MM:SS).
	 * @param array  $retry_scheme    Array of intervals for retrying.
	 * @param int    $retry_position  Position in the retry_scheme.
	 */
	public function send_email( int $order_id, int $event_id, string $to, int $em_type, string $created, array $retry_scheme, int $retry_position ): void {
		global $wpdb;

		$this->mailer->set_retry_scheme( $retry_scheme );
		$this->mailer->set_retry_position( $retry_position );

		if ( MailerInterface::FAST_EVENTS_NORMAL_EMAIL === $em_type || MailerInterface::FAST_EVENTS_CONFIRM_EMAIL === $em_type ) {

			// Look up the order.
			$order_table = $wpdb->prefix . 'fe_event_orders';
			$event_table = $wpdb->prefix . 'fe_events';
			// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
			$result = $wpdb->get_row(
				$wpdb->prepare(
					"SELECT $order_table.id, $order_table.uid, $order_table.payment_status, $order_table.event_id, " .
					"$order_table.input_fields, $order_table.name, $order_table.email, $order_table.created_at, " .
					"$event_table.sender_name, $event_table.sender_email, " .
					"$event_table.email_bcc, $event_table.emails_needed, $event_table.email_subject, " .
					"$event_table.email_body, $event_table.confirm_bcc, $event_table.confirm_subject, " .
					"$event_table.confirm_body, $event_table.redirect " .
					"FROM $order_table " .
					"INNER JOIN $event_table ON $event_table.id = $order_table.event_id " .
					"WHERE $order_table.id = %d",
					$order_id
				)
			);
			// phpcs:enable

			// Does the key exist?
			if ( null === $result ) {
				$this->logger->error(
					/* translators: %d is the order number */
					sprintf( 'Email-retry: ' . esc_html__( 'Order #%d not found', 'fast-events' ), $order_id ),
					array(
						'type'     => 'Email-retry',
						'event_id' => $event_id,
						'order_id' => $order_id,
						'to'       => $to,
					)
				);
				return;
			}
			$result->email      = $to;
			$result->created_at = $created;
		} else {

			// Get the saved message.
			$message = $this->options->get_message( $em_type );
			if ( empty( $message ) ) {
				// Fatal error;  messages nog found -> no retries scheduled.
				$this->logger->error(
					'Fatal email retry for: ' . $to . ', email message not found in cache',
					array(
						'type'     => 'Email-retry',
						'event_id' => $event_id,
						'order_id' => $order_id,
						'to'       => $to,
					)
				);
				return;
			}

			// Check message.
			if ( ! isset( $message['email'] ) || ! isset( $message['hash'] ) ) {
				// Fatal error;  message has illegal format -> no retries.
				$this->logger->error(
					'Fatal email retry for: ' . $to . ', email message not found in cache',
					array(
						'type'     => 'Email-retry',
						'event_id' => $event_id,
						'order_id' => $order_id,
						'to'       => $to,
					)
				);
				return;
			}

			// Check hash.
			if ( wp_hash( JsonUtil::fast_events_json_encode( $message['email'] ) ) !== $message['hash'] ) {
				// Fatal error; illegal hash -> no retries scheduled.
				$this->logger->error(
					'Fatal email retry for: ' . $to . ', email message has illegal hash',
					array(
						'type'     => 'Email-retry',
						'event_id' => $event_id,
						'order_id' => $order_id,
						'to'       => $to,
					)
				);
				return;
			}
			$result = $message['email'];

		}

		// Send the email.
		try {
			// Important that we bypass the queue here, if configured.
			// Failing to do so will result in a deadlock.
			$this->mailer->send_email( $result, $em_type, true );
			// phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
		} catch ( Exception $e ) {
			// Ignore exception as we are in the background. Logging and follow-up were already done in the called function.
		}
	}
}
