<?php

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

class CommunityAllyEmails {
	// <editor-fold defaultstate="collapsed" desc="Notification Emails Settings Display">
	public static function show_notification_emails_settings() {
		// only two emails are applicable in CA 1.1
		$configurable_email_types = array(
			'groups-at-message' => array(
				'header' => 'Mentions',
				'dynamic-text' => array(
					'{{poster.name}}' => 'Poster Name',	// the values are replaced in bp_core_replace_tokens_in_text. double {{ means escaped
					'{{group.name}}' => 'Group Name',
					'{{{mentioned.url}}}' => 'Mention URL',
					'{{{site.name}}}' => 'Site Name',
					'{{usermessage}}' => 'Message content',
					),
				),
			'activity-comment' => array(
				'header' => 'Someone replied to your update',
				'dynamic-text' => array(
					'{{poster.name}}' => 'Poster Name',
					'{{{thread.url}}}' => 'Thread URL',
					'{{{site.name}}}' => 'Site Name',
					'{{usermessage}}' => 'Message content',
					),
				),
			);

		if (CommunityAllySettings::is_messaging_enabled()) {
			$configurable_email_types['messages-unread'] = array(
				'header' => 'Someone sent you a private message',
				'dynamic-text' => array(
					'{{sender.name}}' => 'Sender Name',
					'{{{message.url}}}' => 'Message URL',
					'{{{site.name}}}' => 'Site Name',
					'{{usersubject}}' => 'Message subject',
					'{{usermessage}}' => 'Message content',
					),
				);
		}
		$code = file_get_contents(dirname(__FILE__) . '/settings-notification-emails.php');

		$email_template_code = file_get_contents(dirname(__FILE__) . '/template/settings-notification-email-template.php');
		$content_code = '';
		foreach ($configurable_email_types as $type => $type_settings) {
			$settings = self::get_notification_email_settings($type);
			$individual_email_code = $email_template_code; // to display email as formatted html

			$individual_email_code = str_replace('{{setting-header}}', esc_html($type_settings['header']), $individual_email_code);
			$individual_email_code = str_replace('{{email-type}}', $type, $individual_email_code);

			$modal_opened_class = ($settings['checked-is-open'] === 'yes') ? 'accessally-item-opened' : '';
			$individual_email_code = str_replace('{{modal-opened}}', $modal_opened_class, $individual_email_code);

			$dynamic_text_selection = '';
			foreach ($type_settings['dynamic-text'] as $key => $label) {
				$dynamic_text_selection .= '<option value="' . esc_attr($key) . '">' . esc_html($label) . '</option>';
			}
			$individual_email_code = str_replace('{{dynamic-text-options}}', $dynamic_text_selection, $individual_email_code);

			$elements_code = '';
			foreach ($settings['base-block']['children'] as $element_id) {
				$elements_code .= self::generate_backend_email_template_element_customization($element_id, $settings['element']);
			}
			$individual_email_code = str_replace('{{elements}}', $elements_code, $individual_email_code); // need to generate elements
			$individual_email_code = str_replace('{{setting-name}}', $type, $individual_email_code);
			$individual_email_code = CommunityAllyUtilities::recursive_replace_real_values($individual_email_code, $settings, '', false);
			$individual_email_code = CommunityAllyUtilities::replace_all_toggle($individual_email_code, $settings);

			$content_code .= $individual_email_code;
		}
		$code = str_replace('{{notification-email-code}}', $content_code, $code);
		$current_user = wp_get_current_user();
		$code = str_replace('{{admin-email}}', $current_user->user_email, $code);

		return $code;
	}

	/**
	 *  refer to AA Email $ELEMENT_TYPE for a list of all other elements
	 *
	 * 	@since CommunityAlly 1.1.0
	 */
	private static $CA_EMAIL_ELEMENT_TYPE = array(
		'shared-header' => array(
			'name' => 'Header Block',
			'description' => 'The shared header block configured in Branding',
			'not-allowed-type' => array('shared-block', 'branding'),
			'param' => array(
				'margin-top-bottom' => '0px 0px 0px 0px'
			)
		),
		'shared-footer' => array(
			'name' => 'Footer Block',
			'description' => 'The shared footer block configured in Branding',
			'not-allowed-type' => array('shared-block', 'branding'),
			'param' => array(
				'margin-top-bottom' => '0px 0px 0px 0px'
			)
		),
		'text' => array(
			'name' => 'Regular text',
			'description' => 'Display a regular text message',
			'param' => array(
				'regular-text' => 'Customized text here',
				'margin-top-bottom' => '0px 0px 10px 0px',
				'input-type' => 'mandatory'
			)
		)
	);
	/**
	 * generate customiztion code for individual email element
	 *
	 * @since CommunityAlly 1.1.0
	 */
	private static function generate_backend_email_template_element_customization($element_id, $all_elements) {
		// this is a mirror of the AAEmail function with the same name
		if (!isset($all_elements[$element_id])) {
			return '';
		}
		$element_config = $all_elements[$element_id];
		$element_type = $element_config['type'];
		if (!isset(self::$CA_EMAIL_ELEMENT_TYPE[$element_type])) {
			return '';
		}

		$element_type_config = self::$CA_EMAIL_ELEMENT_TYPE[$element_type];
		$backend_code = file_get_contents(dirname(__FILE__) . '/template/' . $element_type . '-customization.php');

		$preview_code = self::generate_frontend_email_template_element_display($element_id, $all_elements, false);
		$backend_code = str_replace('{{preview-code}}', $preview_code, $backend_code);

		$params = array();
		if (!empty($element_config['param'])) {
			$params = $element_config['param'];
		}
		$params = wp_parse_args($params, $element_type_config['param']);

		$backend_code = self::generate_element_with_params($backend_code, $params);

		/* email element cannot have children in CommunityAlly 1.1
		$child_code = '';
		$backend_code = str_replace('{{children-code}}', $child_code, $backend_code);
		*/

		$customization_code = self::generate_backend_element_parameter_customization($element_config, $element_type_config);
		$backend_code = str_replace('{{customization}}', $customization_code, $backend_code);

		// system element can't be deleted
		if (!empty($element_config['param']['input-type'])) {
			$backend_code = str_replace('{{delete-button}}',
				'<div class="accessally-email-template-notice">Mandatory element cannot be deleted</div>', $backend_code);
		} else {
			$backend_code = str_replace('{{delete-button}}',
				'<div class="accessally-email-template-modal-delete-button accessally-setting-delete-button accessally-general-grey-button" ' .
				'accessally-flex-delete-element="{{email-type}}-{{id}}-{{element-id}}">Delete</div>', $backend_code);
		}

		$backend_code = str_replace('{{element-id}}', $element_id, $backend_code);
		return $backend_code;
	}

	/**
	 * Generate display code for individual email elements
	 */
	private static function generate_frontend_email_template_element_display($element_id, $all_elements, $is_frontend) {
		if (!isset($all_elements[$element_id])) {
			return '';
		}
		$element_config = $all_elements[$element_id];
		$element_type = $element_config['type'];
		if (!isset(self::$CA_EMAIL_ELEMENT_TYPE[$element_type])) {
			return '';
		}

		$element_type_config = self::$CA_EMAIL_ELEMENT_TYPE[$element_type];
		$params = array();
		if (!empty($element_config['param'])) {
			$params = $element_config['param'];
		}
		$params = wp_parse_args($params, $element_type_config['param']);

		$frontend_code = file_get_contents(dirname(__FILE__) . '/front/' . $element_type . '-template.php');

		if ('shared-header' === $element_type) {
			if ($is_frontend) {
				$header_footer = apply_filters('accessally_get_shared_email_header_footer', false);
				$content = $header_footer['shared-header'];
				// we don't want to keep track of actual header footer settings (branding settings) they are kept in AA

				$frontend_code = str_replace('{{content}}', $content, $frontend_code);
			} else {
				$frontend_code = str_replace('{{content}}', 'Brand Header', $frontend_code);
			}
		} elseif ('shared-footer' === $element_type) {
			if ($is_frontend) {
				$header_footer = apply_filters('accessally_get_shared_email_header_footer', false);
				$content = $header_footer['shared-footer'];
				$frontend_code = str_replace('{{content}}', $content, $frontend_code);
			} else {
				$frontend_code = str_replace('{{content}}', 'Brand Footer', $frontend_code);
			}
		}

		$frontend_code = self::generate_element_with_params($frontend_code, $params);

		$frontend_code = str_replace('{{element-id}}', $element_id, $frontend_code);
		return $frontend_code;
	}
	/** refer to AccessAllyEmailTemplateSettings::$PARAMETER_TYPE for more */
	private static $PARAMETER_TYPE = array(
		'margin-top-bottom' => array(
			'param-type' => 'margin-top-bottom',
			'label' => 'Margin'
		),
		'regular-text' => array(
			'param-type' => 'richtext',
			'label' => 'Text'
		),
		'input-type' => array(
			'param-type' => 'hidden',
			'label' => 'System attribute for input'
		),
	);
	private static function generate_backend_element_parameter_customization($element_config, $element_type_config) {
		$customization_code = '';

		foreach ($element_type_config['param'] as $type => $default_value) {
			if (!isset(self::$PARAMETER_TYPE[$type])) {
				throw new Exception('Invalid parameter: ' . $type);
			}
			$param_type_config = self::$PARAMETER_TYPE[$type];
			$param_type_template = $param_type_config['param-type'];
			$param_code = file_get_contents(dirname(__FILE__) . '/template/param/' . $param_type_template . '-param-customization-template.php');

			$param_code = str_replace('{{label}}', esc_html($param_type_config['label']), $param_code);
			$value = $default_value;
			if (isset($element_config['param'][$type])) {
				$value = $element_config['param'][$type];
			}
			$param_code = str_replace('{{value}}', esc_textarea($value), $param_code);
			$param_code = str_replace('{{variable-name}}', $type, $param_code);

			// wp_editor doesn't allow hyphen in the id
			$param_code = str_replace('{{variable-name-underscore}}', str_replace('-', '_', $type), $param_code);

			$customization_code .= $param_code;
		}
		return $customization_code;
	}
	/**
	 * generate parameter clause for regular-text and margin-top-bottom
	 *  refer to generate_param_code in AccessAllyEmailTemplateSettings for more params
	 *
	 *  since CommunityAlly 1.1.0
	 */
	private static function generate_element_with_params($frontend_code, $params) {
		foreach ($params as $key => $value) {
			$frontend_code = str_replace('{{' . $key . '}}', self::generate_param_code($key, $value), $frontend_code);
		}
		return $frontend_code;
	}
	private static function generate_param_code($key, $value) {
		if ('margin-top-bottom' === $key) {
			if (!empty($value)) {
				return 'margin:' . esc_attr($value) . ';';
			}
			return '';
		} elseif ('regular-text' === $key) {
			// do not escape the value, as it is raw HTML
			return $value;
		}
		return esc_html($value);
	}

	const SETTING_KEY_GROUP_AT_MESSAGE = '_communityally_email_group_at_message';
	const SETTING_KEY_ACTIVITY_COMMENT = '_communityally_email_activity_comment';
	const SETTING_KEY_MESSAGES_UNREAD = '_communityally_email_messages_unread';
	private static $EMAIL_TYPE_TO_SETTING_KEY_MAPPING = array(
		'activity-at-message' => self::SETTING_KEY_GROUP_AT_MESSAGE,
		'groups-at-message' => self::SETTING_KEY_GROUP_AT_MESSAGE,
		'activity-comment-author' => self::SETTING_KEY_ACTIVITY_COMMENT, //use the same template to simplify settings
		'activity-comment' => self::SETTING_KEY_ACTIVITY_COMMENT,
		'messages-unread' => self::SETTING_KEY_MESSAGES_UNREAD,
	);
	/**
	 *  Get settings from wp_options or return the default_individual_template_settings for each email type
	 *  (No need to keep track of shared-header / footer params, that information is kept in AA)
	 *  @since CA 1.1.0
	 * */
	public static $default_individual_template_settings = array(
		'element' => array(
			1 => array( 'type' => 'shared-header' ),
			2 => array( 'type' => 'text', 'param' => array( 'regular-text' => '', 'margin-top-bottom' => '20px 0px 20px 0px') ),
			3 => array( 'type' => 'shared-footer' )
		),
		'base-block' => array('children' => array(1, 2, 3)),
		'checked-is-open' => 'no',
		'id' => 0,
		'email-type' => '',
		'setting-header' => '',
		'subject' => ''
	);
	public static function get_notification_email_settings($type) {
		if (!isset(self::$EMAIL_TYPE_TO_SETTING_KEY_MAPPING[$type])) {
			throw new Exception('Email type is not valid');
		}
		$setting_key = self::$EMAIL_TYPE_TO_SETTING_KEY_MAPPING[$type];
		$settings = bp_get_option($setting_key);
		if (empty($settings)) {
			$settings = self::generate_default_email_template_settings($setting_key);
		}

		$settings = self::sanitize_email_template_settings($settings);

		return $settings;
	}

	private static function sanitize_email_template_settings($settings) {
		$settings = wp_parse_args($settings, self::$default_individual_template_settings);
		foreach ($settings['element'] as $element_id => $element_settings) {
			$element_type = $element_settings['type'];
			if (empty($element_settings['param'])) {
				$element_settings['param'] = self::$CA_EMAIL_ELEMENT_TYPE[$element_type]['param'];
			} else {
				$element_settings['param'] = wp_parse_args($element_settings['param'], self::$CA_EMAIL_ELEMENT_TYPE[$element_type]['param']);
			}
			$settings['element'][$element_id] = $element_settings;
		}
		if (!isset($settings['base-block'])) {
			$settings['base-block'] = array('children' => array_keys($settings['element']));
		}
		if (isset($settings['base-block']['children-list'])) {
			if (0 === strlen($settings['base-block']['children-list'])) {
				$settings['base-block']['children'] = array();
			} else {
				$settings['base-block']['children'] = explode(',', $settings['base-block']['children-list']);
			}
			unset($settings['base-block']['children-list']);
		}
		return $settings;
	}
	private static function generate_default_email_template_settings($email_setting_key) {
		$settings = self::$default_individual_template_settings;

		$default_text = array(
			self::SETTING_KEY_ACTIVITY_COMMENT => array(
				'subject' => __( '[{{{site.name}}}] {{poster.name}} replied to one of your comments', 'buddypress' ),
				'content' => __( "{{poster.name}} replied to one of your comments:\n\n<blockquote>&quot;{{usermessage}}&quot;</blockquote>\n\n<a href=\"{{{thread.url}}}\">Go to the discussion</a> to reply or catch up on the conversation.", 'buddypress' ),
				),
			self::SETTING_KEY_GROUP_AT_MESSAGE => array(
				'subject' => __( '[{{{site.name}}}] {{poster.name}} mentioned you in an update', 'buddypress' ),
				'content' => __( "{{poster.name}} mentioned you in the group \"{{group.name}}\":\n\n<blockquote>&quot;{{usermessage}}&quot;</blockquote>\n\n<a href=\"{{{mentioned.url}}}\">Go to the discussion</a> to reply or catch up on the conversation.", 'buddypress' ),
				),
			self::SETTING_KEY_MESSAGES_UNREAD => array(
				'subject' => __( '[{{{site.name}}}] New message from {{sender.name}}', 'buddypress' ),
				'content' => __( "{{sender.name}} sent you a new message: &quot;{{usersubject}}&quot;\n\n<blockquote>&quot;{{usermessage}}&quot;</blockquote>\n\n<a href=\"{{{message.url}}}\">Go to the discussion</a> to reply or catch up on the conversation.", 'buddypress' ),
				),
			);
		$settings['subject'] = $default_text[$email_setting_key]['subject'];
		$settings['element'][2]['param']['regular-text'] = $default_text[$email_setting_key]['content'];

		return $settings;
	}
	// </editor-fold>

	// <editor-fold defaultstate="collapsed" desc="Ajax callback: save eamil settings">
	public static function ajax_save_email_template_settings() {
		try{
			if (!isset($_POST['input']) || !isset($_POST['email_type']) ||
				!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'communityally-update-nonce')) {
				throw new Exception('The setting page is outdated. Please reload this page.');
			}
			$data = stripslashes($_POST['input']);
			$input = CommunityAllyUtilities::convert_setting_string_to_array($data);

			$updated_settings = self::sanitize_email_template_settings($input, $_POST['email_type']);
			$setting_key = self::$EMAIL_TYPE_TO_SETTING_KEY_MAPPING[$_POST['email_type']];

			bp_update_option($setting_key, $updated_settings);

			$result = array('status' => 'success', 'message' => 'Settings have been saved successfully');

			$result['code'] = '';
			$result['warnings'] = '';
			echo json_encode($result);
		} catch (Exception $ex) {
			$error = array('status' => 'error', 'message' => 'Save settings failed due to error [' . $ex->getMessage() . '].');
			echo json_encode($error);
		}
		die();
	}
	// </editor-fold>

	// <editor-fold defaultstate="collapsed" desc="Ajax callback: send test email">
	public static function send_test_email_callback() {
		$result = array('status' => 'error', 'message' => '');
		try {
			if (!isset($_POST['type']) || !isset($_POST['target']) || !isset($_POST['value']) ||
				!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'communityally-update-nonce')) {
				throw new AccessAllyException("Unable to validate request identity. Please refresh the page and make sure you are logged in as an administrator.");
			}

			$email_type = $_POST['type'];
			$target_email = sanitize_text_field($_POST['target']);
			$raw_string = stripslashes($_POST['value']);
			$settings = CommunityAllyUtilities::convert_setting_string_to_array($raw_string);
			$settings = self::sanitize_email_template_settings($settings, $email_type);

			$email_result = self::get_frontend_email_html($settings);
			$email = new BP_Email( $email_type );
			$email->set_content_type('html')
				->set_content_html($email_result['content'])
				->set_subject($email_result['subject']);
			$email->set_to( $target_email );
			// some dummy values for the test email
			$email->set_tokens(array(
				'usermessage' => 'this is a test email',
				'group.name' => 'Wonderful Group',
				'mentioned.url' => 'placeholder-for-url',
				'thread.url' => 'placeholder-for-url',
				'poster.name' => 'Alice',
				'receiver-user.id' =>wp_get_current_user()->ID,
			));
			$status = $email->validate();
			if ( is_wp_error( $status ) ) {
				return $status;
			}
			$to = $email->get( 'to' );
			$headers = array('Content-Type: text/html; charset=UTF-8');

			wp_mail(
				array_shift( $to )->get_address(),
				$email->get( 'subject', 'replace-tokens' ),
				$email->get( 'content', 'replace-tokens' ),
				$headers
			);

			$result['status'] = 'success';
			$result['message'] = 'Test email has been sent to ' . $target_email;
		} catch (Exception $ex) {
			$result = array('status' => 'error', 'message' => $ex->getMessage());
		}
		echo json_encode($result);
		die();
	}
	// </editor-fold>

	// <editor-fold defaultstate="collapsed" desc="Frontend Email html generation">
	public static function get_frontend_email_html($email_settings){
		/** assemble the email here
		 * 	refer to AA generate_frontend_email()
		 */
		$content = self::generate_frontend_email_content($email_settings);
		return array('subject' => $email_settings['subject'], 'content' => $content, 'plaintext' => '');
	}

	private static function generate_frontend_email_content($template_settings) {
		$content = '';
		foreach ($template_settings['base-block']['children'] as $element_id) {
			$content .= self::generate_frontend_email_template_element_display($element_id, $template_settings['element'], true);
		}
		return $content;
	}

	/**
	 * Bypass the BP_PHPMailer in bp_send_email(),
	 * CommunityAlly Emails must sent through wp_mail because BP_PHPMailer is not tested.
	 *
	 * @since CommunityAlly 1.1.0
	 */
	public static function communityally_email_must_use_wp_mail_filter($value) {
		return true;
	}
	// </editor-fold>
}
add_filter('bp_email_use_wp_mail', array('CommunityAllyEmails', 'communityally_email_must_use_wp_mail_filter'));
add_action('wp_ajax_communityally_settings_save_email_template', array('CommunityAllyEmails', 'ajax_save_email_template_settings'));
add_action('wp_ajax_communityally_send_test_email', array('CommunityAllyEmails', 'send_test_email_callback'));
