/home/awneajlw/www/wp-content/plugins/formidable/classes/controllers/FrmEmailStylesController.php
<?php
/**
 * Controller for email styles
 *
 * @since 6.25
 *
 * @package Formidable
 */

if ( ! defined( 'ABSPATH' ) ) {
	die( 'You are not allowed to call this page directly.' );
}

/**
 * Class FrmEmailStylesController
 */
class FrmEmailStylesController {

	/**
	 * Gets email styles.
	 *
	 * @return array[]
	 */
	public static function get_email_styles() {
		$icon_dir_url = FrmAppHelper::plugin_url() . '/images/email-styles/';

		$email_styles = array(
			'classic' => array(
				'name'          => __( 'Classic', 'formidable' ),
				'selectable'    => true,
				'icon_url'      => $icon_dir_url . 'classic.svg',
				'is_plain_text' => false,
			),
			'plain'   => array(
				'name'          => __( 'Plain Text', 'formidable' ),
				'selectable'    => true,
				'icon_url'      => $icon_dir_url . 'plain.svg',
				'is_plain_text' => true,
			),
			'modern'  => array(
				'name'          => __( 'Modern', 'formidable' ),
				'selectable'    => false,
				'icon_url'      => $icon_dir_url . 'modern.svg',
				'is_plain_text' => false,
			),
			'sleek'   => array(
				'name'          => __( 'Sleek', 'formidable' ),
				'selectable'    => false,
				'icon_url'      => $icon_dir_url . 'sleek.svg',
				'is_plain_text' => false,
			),
			'compact' => array(
				'name'          => __( 'Compact', 'formidable' ),
				'selectable'    => false,
				'icon_url'      => $icon_dir_url . 'compact.svg',
				'is_plain_text' => false,
			),
		);

		/**
		 * Filter the email styles.
		 *
		 * @since 6.25
		 *
		 * @param array[] $email_styles The email styles.
		 * @return array
		 */
		return apply_filters( 'frm_email_styles', $email_styles );
	}

	/**
	 * Gets email style preview URL.
	 *
	 * @param string $style_key Style key.
	 * @return string
	 */
	public static function get_email_style_preview_url( $style_key ) {
		return wp_nonce_url( admin_url( 'admin-ajax.php?action=frm_email_style_preview&style_key=' . $style_key ), 'frm_email_style_preview' );
	}

	/**
	 * Gets the email style set in the Global settings.
	 *
	 * @return string
	 */
	public static function get_default_email_style() {
		$frm_settings = FrmAppHelper::get_settings();
		if ( empty( $frm_settings->email_style ) ) {
			return 'classic';
		}

		// Check if the selected style is available and selectable.
		$styles = self::get_email_styles();
		$style  = $frm_settings->email_style;
		if ( isset( $styles[ $style ] ) && ! empty( $styles[ $style ]['selectable'] ) ) {
			return $style;
		}

		return 'classic';
	}

	/**
	 * Gets the test email content.
	 *
	 * @param false|string $style_key Default is `false`, using the one in settings.
	 * @return string
	 */
	private static function get_test_email_content( $style_key = false ) {
		if ( ! $style_key ) {
			$style_key = self::get_default_email_style();
		}

		$table_rows = array(
			array(
				'label' => 'Name',
				'value' => 'John Doe',
			),
			array(
				'label' => 'Email address',
				'value' => 'john@doe.com',
			),
			array(
				'label' => 'Subject',
				'value' => 'Contact subject',
			),
			array(
				'label' => 'Message',
				'value' => 'Lorem ipsum dolor sit amet, <a href="#">consectetur adipiscing elit</a>.
							Praesent in risus velit. Donec molestie tincidunt ex sed consequat. Ut ornare fringilla fringilla.',
			),
		);

		if ( 'plain' !== $style_key ) {
			$content = self::get_test_rich_text_email_content( $style_key, $table_rows );
		} else {
			$content = '';
			foreach ( $table_rows as $row ) {
				$content .= $row['label'] . ': ' . $row['value'] . "\r\n";
			}
		}//end if

		return $content;
	}

	/**
	 * Gets the test email content.
	 *
	 * @param string $style_key  Style key.
	 * @param array  $table_rows Table rows.
	 * @return string
	 */
	private static function get_test_rich_text_email_content( $style_key, $table_rows ) {
		$style_settings = self::get_email_style_settings();

		// Sleek table style doesn't have any border.
		$should_remove_border = 'sleek' === $style_key;

		// Modern and Compact table styles don't have top and bottom border.
		$should_remove_top_bottom_border = 'classic' !== $style_key;

		$table_generator = self::get_table_generator( $style_key );

		$content = $table_generator->generate_table_header();

		// By default, table has the bottom border and table cells have top border.
		if ( $should_remove_top_bottom_border ) {
			$content = $table_generator->remove_border( $content, 'bottom' );
		}

		foreach ( $table_rows as $index => $row ) {
			if ( 'compact' === $style_key ) {
				// Compact table has two columns layout.
				$table_row = $table_generator->generate_two_cell_table_row( $row['label'], $row['value'] );
			} else {
				// Other table styles have one column layout.
				$table_row = $table_generator->generate_single_cell_table_row( self::get_content_for_one_column_cell( $row['label'], $row['value'] ) );
			}

			if ( ! $index && $should_remove_top_bottom_border ) {
				$table_row = $table_generator->remove_border( $table_row );
			}

			$content .= $table_row;
		}

		$content .= $table_generator->generate_table_footer();

		if ( $should_remove_border ) {
			$content = $table_generator->remove_border( $content, 'top' );
		}

		if ( 'classic' !== $style_key ) {
			$content = self::wrap_email_message( $content );
		}

		$wrapped_content = '<html><head><meta charset="utf-8" /></head>';
		if ( 'classic' !== $style_key ) {
			// This works in previewing and as a fallback for email content.
			$wrapped_content .= '<style>
						body {background-color:' . esc_attr( $style_settings['bg_color'] ) . ';}
						a {color:' . esc_attr( $style_settings['link_color'] ) . ';}
					</style>';
		}
		$wrapped_content .= '</head><body>' . $content . '</body></html>';

		return $wrapped_content;
	}

	/**
	 * Gets content for the cell of one column table.
	 *
	 * @param string $label Field label.
	 * @param string $value Prepared field value.
	 * @return string
	 */
	public static function get_content_for_one_column_cell( $label, $value ) {
		return '<div style="font-weight:600;">' . $label . '</div>' . $value;
	}

	/**
	 * Gets table generator object for an email style.
	 *
	 * @param false|string $email_style Email style. Default is `false`: using the one in global settings.
	 * @return FrmTableHTMLGenerator
	 */
	public static function get_table_generator( $email_style = false ) {
		if ( false === $email_style ) {
			$email_style = self::get_default_email_style();
		}

		$style_settings = self::get_email_style_settings();

		$atts = array(
			'inline_style' => true,
			'email_style'  => $email_style,
		);

		if ( 'classic' !== $email_style ) {
			$atts['width']        = '100%';
			$atts['border_color'] = $style_settings['border_color'];
			$atts['cell_padding'] = '16px 0';
			$atts['bg_color']     = $style_settings['container_bg_color'];
			$atts['alt_bg_color'] = $style_settings['container_bg_color'];
			$atts['text_color']   = $style_settings['text_color'];
		}

		return new FrmTableHTMLGenerator( 'entry', $atts );
	}

	/**
	 * AJAX handler for previewing email style.
	 */
	public static function ajax_preview() {
		// Check permission and nonce.
		FrmAppHelper::permission_check( 'frm_change_settings' );
		check_ajax_referer( 'frm_email_style_preview' );

		$style_key     = FrmAppHelper::get_param( 'style_key', '', 'get', 'sanitize_text_field' );
		$not_exist_msg = __( "This email style doesn't exist", 'formidable' );
		if ( ! $style_key ) {
			die( esc_html( $not_exist_msg ) );
		}

		$styles = self::get_email_styles();
		if ( ! isset( $styles[ $style_key ] ) ) {
			die( esc_html( $not_exist_msg ) );
		}

		$style_key = FrmAppHelper::get_param( 'style_key', '', 'sanitize_text_field' );
		$content   = self::get_test_email_content( $style_key );

		header( self::get_content_type_header( $style_key ) );

		echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

		die();
	}

	/**
	 * AJAX handler for sending a test email.
	 */
	public static function ajax_send_test_email() {
		// Check permission and nonce.
		FrmAppHelper::permission_check( 'frm_change_settings' );
		check_ajax_referer( 'frm_ajax', 'nonce' );

		$emails_str   = FrmAppHelper::get_post_param( 'emails_str', '', 'sanitize_text_field' );
		$emails       = explode( ',', $emails_str );
		$valid_emails = array();
		foreach ( $emails as $email ) {
			$email = trim( $email );
			if ( empty( $email ) || ! is_email( $email ) ) {
				continue;
			}
			$valid_emails[] = $email;
		}

		if ( empty( $valid_emails ) ) {
			wp_send_json_error( __( 'Invalid email address', 'formidable' ) );
		}

		$email_style = self::get_default_email_style();

		$subject = __( 'Formidable Test Email', 'formidable' );
		$content = self::get_test_email_content();
		$headers = array(
			self::get_content_type_header( $email_style ),
		);

		FrmUsageController::update_flows_data( 'send_test_email', $email_style );

		$result = wp_mail( $valid_emails, $subject, $content, $headers );
		if ( $result ) {
			wp_send_json_success( __( 'Test email sent successfully!', 'formidable' ) );
		}

		wp_send_json_error( __( 'Failed to send test email!', 'formidable' ) );
	}

	/**
	 * Gets Content-Type header.
	 *
	 * @param string $email_style Email style.
	 * @return string
	 */
	private static function get_content_type_header( $email_style ) {
		$content_type = 'plain' === $email_style ? 'text/plain' : 'text/html';
		return 'Content-Type: ' . $content_type . '; charset=utf-8';
	}

	/**
	 * Shows placeholder Pro settings.
	 */
	public static function show_upsell_settings() {
		include FrmAppHelper::plugin_path() . '/classes/views/frm-settings/email/settings.php';
	}

	/**
	 * Gets email style settings value.
	 *
	 * @return array
	 */
	public static function get_email_style_settings() {
		/**
		 * Filter the email style settings value.
		 *
		 * @since 6.25
		 *
		 * @param array $settings The settings value.
		 */
		return apply_filters(
			'frm_email_style_settings',
			array(
				// Placeholder image.
				'img'                => FrmAppHelper::plugin_url() . '/images/email-styles/placeholder.png',
				'img_size'           => '',
				'img_align'          => '',
				'img_location'       => '',
				'bg_color'           => '#EAECF0',
				'container_bg_color' => '#ffffff',
				'text_color'         => '#475467',
				'link_color'         => '#4199FD',
				'border_color'       => '#dddddd',
				'font'               => '',
			)
		);
	}

	/**
	 * Wraps email message with new settings.
	 *
	 * @param string $message Email message.
	 * @return string
	 */
	public static function wrap_email_message( $message ) {
		$style_settings = self::get_email_style_settings();

		$header_img = '';
		if ( $style_settings['img'] ) {
			$img_align = $style_settings['img_align'] ? $style_settings['img_align'] : 'center';
			$img_size  = $style_settings['img_size'] ? $style_settings['img_size'] : 'thumbnail';
			$img_url   = is_numeric( $style_settings['img'] ) ? wp_get_attachment_image_url( $style_settings['img'], $img_size ) : $style_settings['img'];

			$header_img .= sprintf(
				'<div style="text-align:%s;margin-bottom:32px;">',
				esc_attr( $img_align )
			);

			$header_img .= sprintf(
				'<img src="%s" alt="" style="max-width:100%%;height:auto;" />',
				esc_url( $img_url )
			);

			$header_img .= '</div>';
		}

		// Wrapper.
		$font_family = $style_settings['font'] ? $style_settings['font'] : 'Inter,sans-serif';
		$new_message = sprintf(
			'<div style="background-color:%1$s;color:%2$s;font-family:%3$s;padding:40px 0;">',
			esc_attr( $style_settings['bg_color'] ),
			esc_attr( $style_settings['text_color'] ),
			esc_attr( $font_family )
		);

		// Container.
		$new_message .= '<div style="width:640px;margin:auto;">';

		// Header image if outside.
		if ( $style_settings['img'] && 'inside' !== $style_settings['img_location'] ) {
			$new_message .= $header_img;
		}

		// Main container.
		$new_message .= sprintf(
			'<div style="background-color:%s;border-radius:8px;padding:32px;">',
			esc_attr( $style_settings['container_bg_color'] )
		);

		// Header image if inside.
		if ( $style_settings['img'] && 'inside' === $style_settings['img_location'] ) {
			$new_message .= $header_img;
		}

		// The message.
		$new_message .= self::add_inline_css( 'a', 'color:' . $style_settings['link_color'] . ';', $message );

		$new_message .= '</div></div></div>';

		return $new_message;
	}

	/**
	 * Adds inline CSS to a tag in the content.
	 *
	 * @param string $tag     Tag name.
	 * @param string $css     CSS code.
	 * @param string $content The content.
	 * @return string
	 */
	private static function add_inline_css( $tag, $css, $content ) {
		$regex = '/<' . $tag . '.*?>/msi';
		preg_match_all( $regex, $content, $matches, PREG_SET_ORDER );

		if ( ! $matches ) {
			return $content;
		}

		$searches = array();
		$replaces = array();

		foreach ( $matches as $match ) {
			$searches[] = $match[0];
			$replaces[] = self::add_css_to_style_attr( $tag, $css, $match[0] );
		}

		return str_replace( $searches, $replaces, $content );
	}

	/**
	 * Adds inline CSS to a single HTML tag.
	 *
	 * @param string $tag  Tag name.
	 * @param string $css  CSS code.
	 * @param string $html The HTML tag.
	 * @return string
	 */
	private static function add_css_to_style_attr( $tag, $css, $html ) {
		$regex = '/\sstyle=("|\')/mi';
		if ( preg_match( $regex, $html, $matches ) ) {
			$search  = $matches[0];
			$replace = $search . $css;
			return preg_replace( $regex, $replace, $html );
		}

		return str_replace( '<' . $tag, '<' . $tag . ' style="' . $css . '"', $html );
	}
}