<?php
/**
 * Campaign Customers Exporter
 *
 * @package     EDD\Pro\CampaignTracker\Admin\Exports
 * @copyright   Copyright (c) 2025, Sandhills Development, LLC
 * @license     https://opensource.org/licenses/gpl-2.0.php GNU Public License
 * @since       3.6.3
 */

namespace EDD\Pro\CampaignTracker\Admin\Exports;

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

use EDD\Admin\Exports\Exporters\Exporter;

/**
 * Campaign Customers Exporter Class
 *
 * Exports customers with aggregated campaign data.
 *
 * @since 3.6.3
 */
class CampaignCustomers extends Exporter {

	/**
	 * Number of customers to process per batch.
	 *
	 * @var int
	 */
	protected $per_step = 30;

	/**
	 * Campaign name filter.
	 *
	 * @var string
	 */
	private $campaign = '';

	/**
	 * Set export properties from request data.
	 *
	 * @since 3.6.3
	 * @param array $request Request data from export form.
	 */
	public function set_properties( $request ): void {
		// Handle date filters - check both form field names and simple keys.
		if ( isset( $request['campaign-export-start'] ) ) {
			$this->start = sanitize_text_field( $request['campaign-export-start'] );
		} elseif ( isset( $request['start'] ) ) {
			$this->start = sanitize_text_field( $request['start'] );
		}

		if ( isset( $request['campaign-export-end'] ) ) {
			$this->end = sanitize_text_field( $request['campaign-export-end'] );
		} elseif ( isset( $request['end'] ) ) {
			$this->end = sanitize_text_field( $request['end'] );
		}

		// Handle campaign filter.
		if ( ! empty( $request['campaign_name'] ) ) {
			$this->campaign = sanitize_text_field( $request['campaign_name'] );
		}
	}

	/**
	 * Get the export type identifier.
	 *
	 * @since 3.6.3
	 * @return string Export type.
	 */
	protected function get_export_type(): string {
		return 'campaign_customers';
	}

	/**
	 * Get the CSV column headers.
	 *
	 * @since 3.6.3
	 * @return array Column headers.
	 */
	protected function get_data_headers(): array {
		return array(
			'customer_id'    => __( 'Customer ID', 'easy-digital-downloads' ),
			'customer_name'  => __( 'Customer Name', 'easy-digital-downloads' ),
			'customer_email' => __( 'Customer Email', 'easy-digital-downloads' ),
			'total_spent'    => __( 'Total Spent (Campaign)', 'easy-digital-downloads' ),
			'total_orders'   => __( 'Total Orders (Campaign)', 'easy-digital-downloads' ),
		);
	}

	/**
	 * Get the export data for the current batch.
	 *
	 * @since 3.6.3
	 * @return array Export data rows.
	 */
	protected function get_data(): array {
		$data           = array();
		$customer_stats = $this->get_customer_stats();

		foreach ( $customer_stats as $stat ) {
			$customer = edd_get_customer( $stat->customer_id );

			if ( ! $customer ) {
				continue;
			}

			$data[] = array(
				'customer_id'    => $customer->id,
				'customer_name'  => $customer->name,
				'customer_email' => $customer->email,
				'total_spent'    => edd_format_amount( $stat->total_spent ),
				'total_orders'   => $stat->total_orders,
			);
		}

		return $data;
	}

	/**
	 * Get the total number of customers to export.
	 *
	 * @since 3.6.3
	 * @return int Total customer count.
	 */
	protected function get_total(): int {
		global $wpdb;

		$query = "SELECT COUNT(DISTINCT o.customer_id)
				  FROM {$wpdb->edd_orders} o
				  INNER JOIN {$wpdb->edd_ordermeta} campaign
				    ON (o.id = campaign.edd_order_id AND campaign.meta_key = '_eddct_campaign_name'";

		// Add campaign name filter if specified.
		if ( ! empty( $this->campaign ) ) {
			$query .= ' AND campaign.meta_value = %s';
		}

		$query .= ")
				  {$this->build_where_clause()}";

		if ( ! empty( $this->campaign ) ) {
			return (int) $wpdb->get_var( $wpdb->prepare( $query, $this->campaign ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		}

		return (int) $wpdb->get_var( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
	}

	/**
	 * Get aggregated customer statistics for campaign orders.
	 *
	 * @since 3.6.3
	 * @return array Customer statistics.
	 */
	private function get_customer_stats(): array {
		global $wpdb;

		$per_step = $this->get_per_step();
		$offset   = ( $this->step * $per_step ) - $per_step;
		$where    = $this->build_where_clause();

		$query = "SELECT
					o.customer_id,
					SUM(o.total) as total_spent,
					COUNT(o.id) as total_orders
				  FROM {$wpdb->edd_orders} o
				  INNER JOIN {$wpdb->edd_ordermeta} campaign
				    ON (o.id = campaign.edd_order_id AND campaign.meta_key = '_eddct_campaign_name'";

		// Add campaign name filter if specified.
		if ( ! empty( $this->campaign ) ) {
			$query .= ' AND campaign.meta_value = %s';
		}

		$query .= ")
				  {$where}
				    GROUP BY o.customer_id
				    ORDER BY o.customer_id ASC
				    LIMIT %d OFFSET %d";

		// Prepare the query parameters.
		$params = array();
		if ( ! empty( $this->campaign ) ) {
			$params[] = $this->campaign;
		}
		$params[] = $per_step;
		$params[] = $offset;

		if ( ! empty( $params ) ) {
			$query = $wpdb->prepare( $query, $params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		}

		return $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
	}

	/**
	 * Build the WHERE clause for campaign filtering.
	 *
	 * @since 3.6.3
	 * @return string WHERE clause SQL.
	 */
	private function build_where_clause(): string {
		global $wpdb;

		$where_clauses = array(
			"o.type = 'sale'",
			"o.status IN('complete', 'revoked', 'partially_refunded')",
		);

		// Date range filters.
		if ( ! empty( $this->start ) ) {
			$start_date      = gmdate( 'Y-m-d H:i:s', strtotime( $this->start ) );
			$where_clauses[] = $wpdb->prepare( 'o.date_created >= %s', $start_date );
		}

		if ( ! empty( $this->end ) ) {
			$end_date        = gmdate( 'Y-m-d 23:59:59', strtotime( $this->end ) );
			$where_clauses[] = $wpdb->prepare( 'o.date_created <= %s', $end_date );
		}

		return 'WHERE ' . implode( ' AND ', $where_clauses );
	}
}
