<?php
/**
 * A class that sends email through Mailjet.
 *
 * @since 3.0.0
 */

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

use Exception;
use FeData\FastEvents\Mail\AbstractMailer;
use FeData\FastEvents\Utilities\JsonUtil;
use FeData\FastEvents\Utilities\PluginUtil;
use stdClass;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;

defined( 'ABSPATH' ) || exit;

/**
 * A class that sends email through Mailjet.
 */
final class MailjetMailer extends AbstractMailer {

	/**
	 * Send mail using the Mailjet API.
	 *
	 * @since 1.0
	 * @since 1.9 Added event_id and order_id to the message.
	 * @since 2.5.0 Set provider 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.
	 */
	protected function provider_send( stdClass $order, string $bcc, string $subject, string $msg, int $em_type ): void {
		$this->provider_id = 'mailjet';

		// Sender.
		$sender = array(
			'Email' => $this->get_sender_email( $order ),
			'Name'  => $this->get_sender_name( $order ),
		);

		// Recipient.
		if ( ! empty( $order->name ) ) {
			$rcpt[] = array(
				'Email' => $order->email,
				'Name'  => $order->name,
			);
		} else {
			$rcpt[] = array(
				'email' => $order->email,
			);
		}

		// Is there a BCC?
		if ( ! empty( $bcc ) ) {
			$bcc_rcpt[] = array(
				'email' => $bcc,
			);
		} else {
			$bcc_rcpt = array();
		}

		// Metadata.
		$meta_data = array(
			'Event' => absint( $order->event_id ),
			'Order' => absint( $order->id ),
			'Name'  => $order->name,
		);

		// Prepare the body.
		// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
		$data             = new stdClass();
		$data->Messages[] = array(
			'From'         => $sender,
			'To'           => $rcpt,
			'Bcc'          => $bcc_rcpt,
			'Subject'      => $subject,
			'HTMLPart'     => $msg,
			'TextPart'     => wp_strip_all_tags( $msg ),
			'EventPayload' => JsonUtil::fast_events_json_encode( $meta_data ),
		);
		// phpcs:enable

		// Send the message.
		$response = wp_safe_remote_post(
			$this->settings->mailer_property( 'server' ),
			array(
				'user-agent' => PluginUtil::get_user_agent(),
				'timeout'    => self::CONNECTION_TIMEOUT,
				'headers'    => array(
					// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
					'Authorization' => 'Basic ' . base64_encode( $this->settings->mailer_property( 'api_key' ) ),
					// phpcs:enable
					'Content-Type'  => 'application/json',
				),
				'body'       => JsonUtil::fast_events_json_encode( $data ),
			)
		);

		// Check for errors.
		$this->check_email_provider_api_error( $response, $order, $em_type );
	}

	/**
	 * Extract the email_id used by Mailjet.
	 *
	 * @since 2.5.0
	 *
	 * @param array|WP_Error $response API response from provider.
	 */
	protected function set_email_id( WP_Error|array $response ): void {
		$json           = json_decode( wp_remote_retrieve_body( $response ) );
		$this->email_id = $json->{'Messages'}[0]->{'To'}[0]->{'MessageID'};
	}

	/**
	 * Process the Mailjet events.
	 *
	 * @since 1.9.1
	 * @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
	 */
	public function webhook( WP_REST_Request $data ): WP_REST_Response {
		static $error_events = array( 'bounce', 'spam', 'blocked' );
		$this->provider_id   = 'mailjet';

		$json = json_decode( $data->get_body() );
		if ( json_last_error() !== JSON_ERROR_NONE ) {
			$this->logger->error(
				'JSON error: ' . json_last_error_msg() . PHP_EOL . PHP_EOL . $data->get_body(),
				array( 'type' => 'Email-' . $this->provider_id )
			);
			return rest_ensure_response( 'Ok' );
		}

		// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
		$event_id = 0;
		$order_id = 0;
		if ( isset( $json->EventPayload ) ) {
			$meta = json_decode( $json->EventPayload );
			if ( json_last_error() === JSON_ERROR_NONE ) {
				$event_id = absint( $meta->Event ?? 0 );
				$order_id = absint( $meta->Order ?? 0 );
			}
		}
		// phpcs:enable
		if ( isset( $json->event ) && in_array( $json->event, $error_events, true ) ) {
			$this->logger->info(
			/* translators: %s is the email provider event name, and the last %s is the provider email id */
				sprintf( __( 'Adding the "%1$s" event to email-id "%1$s": ', 'fast-events' ), $json->event, $json->{'MessageID'} ),
				array(
					'type'     => 'Email-' . $this->provider_id,
					'event_id' => $event_id,
					'order_id' => $order_id,
					'event'    => $json,
				)
			);
		}

		$this->update_email_log( $json->{'MessageID'}, $json, $event_id, $order_id );

		return rest_ensure_response( 'Ok' );
	}
}
