<?php
/**
 * Email Summary Class.
 *
 * @package     EDD
 * @subpackage  Emails
 * @copyright   Copyright (c) 2022, Easy Digital Downloads, LLC
 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
 * @since       3.1
 */

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

/**
 * EDD_Email_Summary Class.
 *
 * Takes care of preparing the necessary dataset, building the
 * email template and sending the Email Summary.
 *
 * @since 3.1
 */
class EDD_Email_Summary {

	/**
	 * Are we in a test mode.
	 *
	 * @since 3.1
	 *
	 * @var bool
	 */
	private $test_mode;

	/**
	 * Email options.
	 *
	 * @since 3.1
	 *
	 * @var string
	 */
	private $email_options;

	/**
	 * Image URI Path
	 *
	 * @since 3.1.1
	 *
	 * @var string
	 */
	private $image_path = 'https://plugin.easydigitaldownloads.com/cdn/summaries/';

	/**
	 * Date ranges.
	 *
	 * @since 3.3.7
	 * @var array
	 */
	private $date_ranges;

	/**
	 * Class constructor.
	 *
	 * @since 3.1
	 */
	public function __construct( $test_mode = false ) {
		$this->test_mode     = $test_mode;
		$this->email_options = array(
			'email_summary_frequency' => edd_get_option( 'email_summary_frequency', 'weekly' ),
		);
	}

	/**
	 * Get site URL.
	 *
	 * @since 3.1
	 *
	 * @return string Host of the site url.
	 */
	public function get_site_url() {
		$site_url        = get_site_url();
		$site_url_parsed = wp_parse_url( $site_url );
		$site_url        = isset( $site_url_parsed['host'] ) ? $site_url_parsed['host'] : $site_url;

		return $site_url;
	}

	/**
	 * Get email subject.
	 *
	 * @since 3.1
	 *
	 * @return string Email subject.
	 */
	public function get_email_subject() {
		/* translators: Site domain name */
		$email_subject = sprintf( __( 'Easy Digital Downloads Summary - %s', 'easy-digital-downloads' ), $this->get_site_url() );

		if ( $this->test_mode ) {
			$email_subject = '[TEST] ' . $email_subject;
		}

		return $email_subject;
	}

	/**
	 * Get email recipients.
	 *
	 * @since 3.1
	 *
	 * @return array Recipients to receive the email.
	 */
	public function get_email_recipients() {
		$recipients = array();

		if ( 'admin' === edd_get_option( 'email_summary_recipient', 'admin' ) ) {
			$recipients[] = get_option( 'admin_email' );
		} else {
			$emails = edd_get_option( 'email_summary_custom_recipients', '' );
			$emails = array_map( 'trim', explode( "\n", $emails ) );
			foreach ( $emails as $email ) {
				if ( is_email( $email ) ) {
					$recipients[] = $email;
				}
			}
		}

		if ( empty( $recipients ) ) {
			edd_debug_log( __( 'Missing email recipients for Email Summary', 'easy-digital-downloads' ), true );
		}

		return apply_filters( 'edd_email_summary_recipients', $recipients );
	}

	/**
	 * Retrieve ! TEST ! dataset for email content.
	 *
	 * @since 3.1
	 *
	 * @return array Data and statistics for the period.
	 */
	public function get_test_report_dataset() {
		$stats = new EDD\Stats();
		$args  = array(
			'post_type'      => 'download',
			'posts_per_page' => 5,
			'fields'         => 'ids',
			'no_found_rows'  => true,
		);

		$downloads            = new WP_Query( $args );
		$top_selling_products = array();

		foreach ( $downloads->posts as $post ) {
			$download = new EDD_Download( $post );

			$product         = new stdClass();
			$product->object = $download;
			$product->total  = 100;

			$top_selling_products[] = $product;
		}

		$data = array(
			'earnings_gross'       => array(
				'value'         => 5000,
				'relative_data' => $stats->generate_relative_data( 5000, 4000 ),
			),
			'earnings_net'         => array(
				'value'         => 4500,
				'relative_data' => $stats->generate_relative_data( 4500, 3500 ),
			),
			'average_order_value'  => array(
				'value'         => 29,
				'relative_data' => $stats->generate_relative_data( 20, 35 ),
			),
			'new_customers'        => array(
				'value'         => 25,
				'relative_data' => $stats->generate_relative_data( 25, 20 ),
			),
			'top_selling_products' => $top_selling_products,
			'order_count'          => array( 'value' => 172 ),
		);

		return $data;
	}

	/**
	 * Retrieve dataset for email content.
	 *
	 * @since 3.1
	 *
	 * @return array Data and statistics for the period.
	 */
	public function get_report_dataset() {
		if ( $this->test_mode ) {
			return $this->get_test_report_dataset();
		}

		$date_range          = $this->get_report_date_range();
		$start_date          = $date_range['start_date']->format( 'Y-m-d H:i:s' );
		$end_date            = $date_range['end_date']->format( 'Y-m-d H:i:s' );
		$relative_start_date = $date_range['relative_start_date']->format( 'Y-m-d H:i:s' );
		$relative_end_date   = $date_range['relative_end_date']->format( 'Y-m-d H:i:s' );
		$stats               = new EDD\Stats(
			array(
				'output'         => 'array',
				'start'          => $start_date,
				'end'            => $end_date,
				'relative'       => true,
				'relative_start' => $relative_start_date,
				'relative_end'   => $relative_end_date,
			)
		);

		$earnings_gross = $stats->get_order_earnings(
			array(
				'function'      => 'SUM',
				'exclude_taxes' => false,
				'revenue_type'  => 'gross',
			)
		);

		$earnings_net = $stats->get_order_earnings(
			array(
				'function'      => 'SUM',
				'exclude_taxes' => true,
				'revenue_type'  => 'net',
			)
		);

		$average_order_value = $stats->get_order_earnings(
			array(
				'function'      => 'AVG',
				'exclude_taxes' => false,
			)
		);

		$new_customers = $stats->get_customer_count(
			array(
				'purchase_count' => true,
			)
		);

		$top_selling_products = $stats->get_most_valuable_order_items(
			array(
				'number' => 5,
			)
		);

		$order_count = $stats->get_order_count();

		return compact(
			'earnings_gross',
			'earnings_net',
			'average_order_value',
			'new_customers',
			'top_selling_products',
			'order_count'
		);
	}

	/**
	 * Generate HTML for relative markup.
	 *
	 * @since 3.1
	 *
	 * @param array $relative_data Calculated relative data.
	 *
	 * @return string HTML for relative markup.
	 */
	private function build_relative_markup( $relative_data ) {
		$arrow  = $relative_data['positive_change'] ? 'icon-arrow-up.png' : 'icon-arrow-down.png';
		$output = __( 'No data to compare', 'easy-digital-downloads' );
		if ( $relative_data['no_change'] ) {
			$output = __( 'No Change', 'easy-digital-downloads' );
		} elseif ( $relative_data['comparable'] ) {
			$output = $relative_data['formatted_percentage_change'] . '%';
		}
		ob_start();
		?>
		<?php if ( $relative_data['comparable'] ) : ?>
			<img src="<?php echo esc_url( $this->image_path . $arrow ); ?>" width="12" height="10" style="outline: none; text-decoration: none; -ms-interpolation-mode: bicubic; width: 12px; height: 10px; max-width: 100%; clear: both; vertical-align: text-top;">
		<?php endif; ?>
		<span style="padding-left: 1px;">
			<?php echo esc_html( $output ); ?>
		</span>
		<?php

		return ob_get_clean();
	}

	/**
	 * Build email template.
	 *
	 * @since 3.1
	 *
	 * @param array|bool $blurb Structured blurb data.
	 *
	 * @return string|bool The string of the email template or false if the email template couldn't be built.
	 */
	public function build_email_template( $blurb = false ) {
		$dataset = $this->get_report_dataset();
		// If there were no sales, do not build an email template.
		if ( empty( $dataset['order_count'] ) || 0 === $dataset['order_count'] ) {
			return false;
		}

		$date_range     = $this->get_report_date_range();
		$site_url       = get_site_url();
		$view_more_url  = edd_get_admin_url(
			array(
				'page'           => 'edd-reports',
				'range'          => ( 'monthly' === $this->email_options['email_summary_frequency'] ) ? 'last_month' : 'last_week',
				'relative_range' => 'previous_period',
			)
		);
		$wp_date_format = get_option( 'date_format' );
		$period_name    = ( 'monthly' === $this->email_options['email_summary_frequency'] ) ? __( 'month', 'easy-digital-downloads' ) : __( 'week', 'easy-digital-downloads' );
		/* translators: period name (e.g. week) */
		$relative_text = sprintf( __( 'vs previous %s', 'easy-digital-downloads' ), $period_name );

		ob_start();
		include EDD_PLUGIN_DIR . 'includes/emails/email-summary/edd-email-summary-template.php';

		return ob_get_clean();
	}

	/**
	 * Prepare and send email.
	 *
	 * @since 3.1
	 *
	 * @return bool True if email was sent, false if there was an error.
	 */
	public function send_email() {
		// Get next blurb.
		$email_blurbs = new EDD_Email_Summary_Blurb();
		$next_blurb   = false;

		if ( ! $this->test_mode ) {
			$next_blurb = $email_blurbs->get_next();
		}

		// Prepare email.
		$email_body = $this->build_email_template( $next_blurb );
		// If there is no email body, we cannot continue.
		if ( ! $email_body ) {
			edd_debug_log( __( 'Email body for Email Summary was empty.', 'easy-digital-downloads' ), true );
			return false;
		}

		$email_subject    = $this->get_email_subject();
		$email_recipients = $this->get_email_recipients();
		$email_headers    = array( 'Content-Type: text/html; charset=UTF-8' );

		// Everything is ok, send email.
		$email_sent = wp_mail( $email_recipients, $email_subject, $email_body, $email_headers );
		if ( $email_sent ) {
			$email_blurbs->mark_blurb_sent( $next_blurb );
		}

		return $email_sent;
	}

	/**
	 * Get report date range.
	 *
	 * @since 3.1
	 * @return array Array of start and end date objects in \EDD\Utils\Date[] format.
	 */
	public function get_report_date_range() {
		if ( ! is_null( $this->date_ranges ) ) {
			return $this->date_ranges;
		}

		$range          = 'last_week';
		$previous_range = 'previous_period';
		if ( 'monthly' === $this->email_options['email_summary_frequency'] ) {
			$range          = 'last_month';
			$previous_range = 'previous_month';
		}

		require_once EDD_PLUGIN_DIR . 'includes/reports/reports-functions.php';
		$parsed_dates          = \EDD\Reports\parse_dates_for_range( $range );
		$parsed_relative_dates = \EDD\Reports\parse_relative_dates_for_range( $range, $previous_range );

		$this->date_ranges = array(
			'start_date'          => $parsed_dates['start'],
			'end_date'            => $parsed_dates['end'],
			'relative_start_date' => $parsed_relative_dates['start'],
			'relative_end_date'   => $parsed_relative_dates['end'],
		);

		return $this->date_ranges;
	}

	/**
	 * Get report start date.
	 *
	 * @since 3.1
	 * @deprecated 3.3.7
	 * @return EDD\Utils\Date An array of start date and its relative counterpart as the EDD date object set at the UTC equivalent time.
	 */
	public function get_report_start_date() {
		$ranges = $this->get_report_date_range();

		return array(
			'start_date'          => $ranges['start_date'],
			'relative_start_date' => $ranges['relative_start_date'],
		);
	}

	/**
	 * Get report end date.
	 *
	 * @since 3.1
	 * @deprecated 3.3.7
	 * @return EDD\Utils\Date An array of end date and its relative counterpart as the EDD date object set at the UTC equivalent time.
	 */
	public function get_report_end_date() {

		$ranges = $this->get_report_date_range();

		return array(
			'end_date'          => $ranges['end_date'],
			'relative_end_date' => $ranges['relative_end_date'],
		);
	}
}
