<?php
/**
 * A class that sends email through the local email system.
 *
 * @since 3.0.0
 */

declare( strict_types=1 );
namespace FeData\FastEvents\Mail\Provider;

use Exception;
use FeData\FastEvents\Mail\AbstractMailer;
use FeData\FastEvents\Utilities\UniqIds;
use PHPMailer\PHPMailer\PHPMailer;
use stdClass;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;

defined( 'ABSPATH' ) || exit;

/**
 * A class that sends email through the local email system.
 */
final class LocalMailer extends AbstractMailer {

	/**
	 * The PHPMailer class
	 *
	 * @since 1.0
	 * @var ?object
	 */
	private ?object $phpmailer = null;

	/**
	 * Send SMTP email (local mail or smtp)
	 *
	 * @since 1.0
	 * @since 2.1 - Use 'filter in 'get_sender_name' and 'get_sender_email'.
	 *            - Escape error.
	 * @since 2.5.0 Set provider id and email id.
	 *
	 * @param stdClass $order   Order information.
	 * @param string   $bcc     Emailaddress of BBC receiver.
	 * @param string   $subject Subject of the email.
	 * @param string   $msg     HTML mail message.
	 * @param int      $em_type 0=Normal mail, 1=Confirmation email.
	 *
	 * @throws Exception If mail can't be sent or invalid from-address.
	 */
	protected function provider_send( stdClass $order, string $bcc, string $subject, string $msg, int $em_type ): void {
		$this->provider_id = 'local';

		// Initialize vars for possible 'fast_events_email_api_result'-action usage.
		$http_code     = 200;
		$error_message = '';

		try {
			// Is PHPMailer initialised?
			if ( ! ( $this->phpmailer instanceof PHPMailer ) ) {
				require_once ABSPATH . WPINC . '/PHPMailer/Exception.php';
				require_once ABSPATH . WPINC . '/PHPMailer/SMTP.php';
				require_once ABSPATH . WPINC . '/PHPMailer/PHPMailer.php';
				$this->phpmailer = new PHPMailer( true );
			}

			$this->phpmailer->CharSet = apply_filters(
				'fast_events_mail_charset',
				get_bloginfo( 'charset' ),
				(int) $order->id,
				$order->payment_status,
				(int) $order->event_id,
				$order->name,
				$order->email
			);

			$this->email_id = UniqIds::uniq_order_id(); // Not used, but needed for compatibility.

			// Clear addresses and other possible usage.
			$this->phpmailer->clearAllRecipients();
			$this->phpmailer->clearAttachments();
			$this->phpmailer->clearCustomHeaders();
			$this->phpmailer->clearReplyTos();

			// Set the sender.
			$this->phpmailer->setFrom( $this->get_sender_email( $order ), $this->get_sender_name( $order ) );

			// Recipient.
			$this->phpmailer->addAddress( $order->email, $order->name );

			// Is there a BCC?
			if ( ! empty( $bcc ) ) {
				$this->phpmailer->addBCC( $bcc );
			}

			// Content.
			$this->phpmailer->isHTML();
			$this->phpmailer->Subject = $subject;
			$this->phpmailer->Sender  = $this->get_sender_email( $order );
			$this->phpmailer->Body    = $msg;
			$this->phpmailer->AltBody = $this->phpmailer->html2text( $msg );
			$this->phpmailer->XMailer = ' ';
			$this->phpmailer->Timeout = self::CONNECTION_TIMEOUT;

			// Send it.
			$this->phpmailer->send();
		} catch ( \PHPMailer\PHPMailer\Exception $e ) {
			$http_code = 400;
			$error     = '{"Description": "' . $e->getMessage() . '"}';
			$this->logger->error(
				'PHPMailer error: ' . $e->getMessage(),
				array(
					'type'     => 'Email-' . $this->provider_id,
					'event_id' => (int) $order->event_id,
					'order_id' => (int) $order->id,
				)
			);

			// Check for a retry scheme.
			$this->check_email_retry_scheme( $order, $error_message, $em_type );

			throw new Exception( esc_html( $error ) );
		} finally {
			if ( 200 === $http_code ) {
				$this->email_delivered( $order, $em_type );
			}

			/**
			 * Action to use the results of the 'Host email' or 'SMTP' PHPMail usage.
			 *
			 * @since 1.0
			 *
			 * @param int    $http_code The HTTP resultcode of the API.
			 * @param int    $order_id  The id of the order.
			 * @param string $email     Emailaddress of recipient.
			 * @param string $result    The body of the API-call result.
			 */
			do_action( 'fast_events_email_api_result', $http_code, (int) $order->id, $order->email, $error_message );
		}
	}

	/**
	 * Extract the email_id used by the local mailhost; we just create a unique ID.
	 *
	 * @since 2.5.0
	 *
	 * @param array|WP_Error $response API response from provider.
	 */
	protected function set_email_id( WP_Error|array $response ): void {
		$this->email_id = UniqIds::uniq_order_id();
	}

	/**
	 * Process the Amazon SES webhook events.
	 *
	 * @since 2.4.0
	 * @since 2.5.0 All events are added to the email log, and error events are added to the errorlog as well.
	 *
	 * @param WP_REST_Request $data Request instance.
	 *
	 * @return WP_REST_Response | WP_Error
	 */
	public function webhook( WP_REST_Request $data ): WP_Error|WP_REST_Response {
		$this->provider_id = 'local';
		return new WP_Error( 'not_used', __( 'This local mailer does not support webhooks.', 'fast-events' ) );
	}
}
