<?php

namespace WC_Affiliate\Controllers\Common;

use WC_Affiliate\Helpers\Email\Mailer;
use WC_Affiliate\Helpers\Email\Messages;
use WC_Affiliate\Models\Affiliate;
use WC_Affiliate\Models\Referral;
use WC_Affiliate\Models\Transaction;

defined( 'ABSPATH' ) || exit;

/**
 * Email Controller for WC Affiliate Plugin.
 *
 * Handles email-related operations including sending various types of emails
 * to affiliates and administrators. Delegates email sending to the Email helper
 * for template rendering and delivery.
 *
 * @since 1.0.0
 */
class Email {

	/**
	 * The mail sender.
	 *
	 * @var Mailer $mailer
	 */
	protected Mailer $mailer;

	/**
	 * @var Messages
	 */
	protected Messages $messages;

	/**
	 * Controller constructor
	 *
	 * Automatically registers email hooks on instantiation
	 */
	public function __construct() {
		$this->register_hooks();

		$this->mailer   = new Mailer();
		$this->messages = new Messages();
	}

	/**
	 * Register hooks for email controller
	 *
	 * @return void
	 */
	protected function register_hooks(): void {
		// Core email sending hooks.
		add_action( 'wc_affiliate_affiliate_applied', array( $this, 'send_affiliate_applied_emails' ), 10, 2 );
		add_action( 'wc_affiliate_affiliate_updated', array( $this, 'send_account_status_update_email' ), 10, 2 );
		add_action( 'wc_affiliate_account_reviewed', array( $this, 'send_account_review_email' ), 10, 2 );
		add_action( 'wc_affiliate_payout_request_created', array( $this, 'send_payout_request_emails' ), 10, 2 );
		add_action( 'wc_affiliate_add_credit', array( $this, 'send_credit_added_emails' ), 10, 3 );
		add_action( 'wc_affiliate_payout_processed', array( $this, 'send_payout_processed_email' ), 10, 3 );
		add_filter( 'wc_affiliate_resend_verification_email', array( $this, 'resend_verification_email' ), 10, 2 );

		// Additional email hooks for better extensibility.
		add_action( 'wc_affiliate_transaction_after_create', array( $this, 'handle_transaction_emails' ), 10, 2 );
		add_action( 'wc_affiliate_referral_has_paid', array( $this, 'handle_paid_referral_emails' ), 10, 3 );

		// Report email hooks from Process controller.
		// add_action( 'wc_affiliate_send_daily_summary', array( $this, 'send_daily_summary' ), 10, 0 );
		// add_action( 'wc_affiliate_send_weekly_reports', array( $this, 'send_weekly_reports' ), 10, 0 );
	}

	/**
	 * Send affiliate applied emails (both affiliate and admin)
	 *
	 * @param int   $user_id        User ID.
	 * @param array $affiliate_data Affiliate data array.
	 *
	 * @return void
	 */
	public function send_affiliate_applied_emails( int $user_id, array $affiliate_data ): void {
		$affiliate_email_data = $this->messages->compose_affiliate_applied_affiliate( $user_id, $affiliate_data );
		if ( $affiliate_email_data['enabled'] ) {
			foreach ( $affiliate_email_data['recipients'] as $recipient_email ) {
				$this->mailer->send(
					$recipient_email,
					$affiliate_email_data['subject'],
					$affiliate_email_data['content'],
					$affiliate_email_data['context']
				);
			}

			/**
			 * Action fired after sending affiliate application email
			 *
			 * @param int   $user_id              User ID of the affiliate
			 * @param array $affiliate_email_data Email data that was sent
			 */
			do_action( 'wc_affiliate_after_send_affiliate_applied_email', $user_id, $affiliate_email_data );
		}

		$admin_email_data = $this->messages->compose_affiliate_applied_admin( $user_id, $affiliate_data );
		if ( $admin_email_data['enabled'] ) {
			foreach ( $admin_email_data['recipients'] as $recipient_email ) {
				$this->mailer->send(
					$recipient_email,
					$admin_email_data['subject'],
					$admin_email_data['content'],
					$admin_email_data['context'],
					true, // is_admin_email.
				);
			}

			/**
			 * Action fired after sending affiliate application email to admin
			 *
			 * @param int   $user_id          User ID of the affiliate
			 * @param array $admin_email_data Email data that was sent
			 */
			do_action( 'wc_affiliate_after_send_affiliate_admin_email', $user_id, $admin_email_data );
		}
	}

	/**
	 * Send account status update email to affiliate when status changes
	 *
	 * Checks if the affiliate status has changed and sends appropriate notification emails
	 * for account approval or rejection.
	 *
	 * @param int   $affiliate_id Affiliate ID.
	 * @param array $update_data  Array containing status update data with 'status' and 'old_status' keys.
	 *
	 * @return void
	 */
	public function send_account_status_update_email( int $affiliate_id, array $update_data ): void {
		if ( empty( $update_data['status'] ) && empty( $update_data['old_status'] ) ) {
			return;
		}

		if ( 'active' === $update_data['status'] && 'active' !== $update_data['old_status'] ) {
			$this->send_account_review_email( $affiliate_id, 'approve' );
		}

		if ( 'rejected' === $update_data['status'] && 'rejected' !== $update_data['old_status'] ) {
			$this->send_account_review_email( $affiliate_id, 'reject' );
		}
	}

	/**
	 * Send account review email to affiliate
	 *
	 * @param int    $user_id       User ID.
	 * @param string $review_action Review action (approve/reject).
	 *
	 * @return void
	 */
	public function send_account_review_email( int $user_id, string $review_action ): void {
		$review_email_data = $this->messages->compose_account_review_affiliate( $user_id, $review_action );
		if ( $review_email_data['enabled'] ) {
			foreach ( $review_email_data['recipients'] as $recipient ) {
				$this->mailer->send(
					$recipient,
					$review_email_data['subject'],
					$review_email_data['content'],
					$review_email_data['context']
				);
			}

			do_action( 'wc_affiliate_after_send__account_review_email', $user_id, $review_email_data, $review_action );
		}
	}

	/**
	 * Send payout request emails (both affiliate and admin)
	 *
	 * @param float     $available_balance Available balance for payout.
	 * @param Affiliate $affiliate         Affiliate model instance.
	 *
	 * @return void
	 */
	public function send_payout_request_emails( float $available_balance, Affiliate $affiliate ): void {
		$affiliate_email_data = $this->messages->compose_request_payout_affiliate( $affiliate, $available_balance );
		if ( $affiliate_email_data['enabled'] ) {
			foreach ( $affiliate_email_data['recipients'] as $recipient_email ) {
				$this->mailer->send(
					$recipient_email,
					$affiliate_email_data['subject'],
					$affiliate_email_data['content'],
					$affiliate_email_data['context']
				);
			}

			do_action( 'wc_affiliate_after_send_request_payout_affiliate', $affiliate, $affiliate );
		}

		$admin_email_data = $this->messages->compose_request_payout_admin( $affiliate, $available_balance );
		if ( $admin_email_data['enabled'] ) {
			foreach ( $admin_email_data['recipients'] as $recipient_email ) {
				$this->mailer->send(
					$recipient_email,
					$admin_email_data['subject'],
					$admin_email_data['content'],
					$admin_email_data['context'],
					true // is_admin_email.
				);
			}

			do_action( 'wc_affiliate_after_send_request_payout_admin_email', $affiliate, $admin_email_data );
		}
	}

	/**
	 * Send credit added emails (both affiliate and admin)
	 *
	 * @param int   $affiliate_id  Affiliate ID.
	 * @param int   $order_id      Order ID.
	 * @param array $referral_data Referral data.
	 *
	 * @return void
	 */
	public function send_credit_added_emails( int $affiliate_id, int $order_id, array $referral_data ): void {
		$affiliate_email_data = $this->messages->compose_add_credit_affiliate( $affiliate_id, $order_id, $referral_data );
		if ( $affiliate_email_data['enabled'] ) {
			foreach ( $affiliate_email_data['recipients'] as $recipient_email ) {
				$this->mailer->send(
					$recipient_email,
					$affiliate_email_data['subject'],
					$affiliate_email_data['content'],
					$affiliate_email_data['context']
				);
			}

			do_action( 'wc_affiliate_after_send_credit_affiliate_email', $affiliate_id, $affiliate_email_data );
		}

		$admin_email_data = $this->messages->compose_add_credit_admin( $affiliate_id, $order_id, $referral_data );
		if ( $admin_email_data['enabled'] ) {
			foreach ( $admin_email_data['recipients'] as $recipient_email ) {
				$this->mailer->send(
					$recipient_email,
					$admin_email_data['subject'],
					$admin_email_data['content'],
					$admin_email_data['context'],
					true // is_admin_email.
				);
			}

			do_action( 'wc_affiliate_after_send_add_credit_admin_email', $affiliate_id, $admin_email_data );
		}
	}

	/**
	 * Send payout processed email to affiliate
	 *
	 * @param int   $affiliate_id     Affiliate ID.
	 * @param float $amount           Payout amount.
	 * @param array $transaction_data Transaction data array.
	 *
	 * @return void
	 */
	public function send_payout_processed_email( int $affiliate_id, float $amount, array $transaction_data ): void {
		$affiliate_email_data = $this->messages->compose_payout_processed( $affiliate_id, $amount, $transaction_data );
		if ( $affiliate_email_data['enabled'] ) {
			foreach ( $affiliate_email_data['recipients'] as $recipient_email ) {
				$this->mailer->send(
					$recipient_email,
					$affiliate_email_data['subject'],
					$affiliate_email_data['content'],
					$affiliate_email_data['context']
				);
			}

			do_action( 'wc_affiliate_email_send_payout_processed_email', $affiliate_id, $affiliate_email_data );
		}
	}

	/**
	 * Handle transaction inserted emails
	 *
	 * @param int         $transaction_id Transaction ID.
	 * @param Transaction $transaction    Transaction model instance.
	 *
	 * @return void
	 */
	public function handle_transaction_emails( int $transaction_id, Transaction $transaction ): void {
		$admin_email_data = $this->messages->compose_transaction_created_admin( $transaction_id, $transaction );

		if ( $admin_email_data['enabled'] ) {
			$this->mailer->send(
				$admin_email_data['recipients'],
				$admin_email_data['subject'],
				$admin_email_data['content'],
				$admin_email_data['context'],
				true // is_admin_email.
			);

			do_action( 'wc_affiliate_email_send_transaction_created_admin_email', $transaction_id, $transaction );
		}
	}

	/**
	 * Handle paid referral emails
	 *
	 * @param int         $referral_id Referral ID.
	 * @param Referral    $referral    Referral model instance.
	 * @param Transaction $transaction Transaction model instance.
	 *
	 * @return void
	 */
	public function handle_paid_referral_emails( int $referral_id, Referral $referral, Transaction $transaction ): void {
		$affiliate_email_data = $this->messages->compose_paid_referral_affiliate( $referral_id, $referral, $transaction );
		if ( $affiliate_email_data['enabled'] ) {
			$this->mailer->send(
				$affiliate_email_data['recipients'],
				$affiliate_email_data['subject'],
				$affiliate_email_data['content'],
				$affiliate_email_data['context']
			);

			do_action( 'wc_affiliate_email_send_paid_referral_email', $referral_id, $referral, $transaction );
		}

		$admin_email_data = $this->messages->compose_paid_referral_admin( $referral_id, $referral, $transaction );
		if ( $admin_email_data['enabled'] ) {
			$this->mailer->send(
				$admin_email_data['recipients'],
				$admin_email_data['subject'],
				$admin_email_data['content'],
				$admin_email_data['context'],
				true // is_admin_email.
			);

			do_action( 'wc_affiliate_email_send_paid_referral_admin_email', $referral_id, $referral, $transaction );
		}
	}

	/**
	 * Resend verification email filter
	 *
	 * @param array $response Response array.
	 * @param mixed $user     User object (WP_User).
	 *
	 * @return array Modified response
	 */
	public function resend_verification_email( array $response, $user ): array {
		$email_data = $this->messages->compose_verification_resend( $user );

		if ( ! $email_data['enabled'] ) {
			$response['message'] = \__( 'Email validation is disabled.', 'wc-affiliate' );

			return $response;
		}

		foreach ( $email_data['recipients'] as $recipient ) {
			$this->mailer->send(
				$recipient,
				$email_data['subject'],
				$email_data['content'],
				$email_data['context']
			);
		}

		$response['status']  = 1;
		$response['message'] = \__( 'Verification email has been sent successfully. Please check your inbox and spam folder.', 'wc-affiliate' );

		return $response;
	}

	// **
	// * Send daily summary email
	// *
	// * @param string $email Admin email address.
	// * @param array  $stats Daily statistics.
	// * @param string $date  Date for the summary.
	// */
	// public function send_daily_summary_email( string $email, array $stats, string $date ) {
	// $email_data = $this->messages->compose_daily_summary( $email, $stats, $date );
	// if ( $email_data['enabled'] ) {
	// foreach ( $email_data['recipients'] as $recipient ) {
	// $this->mailer->send(
	// $recipient,
	// $email_data['subject'],
	// $email_data['content'],
	// $email_data['context'],
	// true // is_admin_email.
	// );
	// }
	//
	// do_action( 'wc_affiliate_email_send_daily_summary_email', $email, $stats, $date );
	// }
	// }
	//
	// **
	// * Send weekly report email
	// *
	// * @param string $email        Admin email address.
	// * @param array  $weekly_stats Weekly statistics.
	// * @param string $start_date   Start date.
	// * @param string $end_date     End date.
	// */
	// public function send_weekly_report_email( string $email, array $weekly_stats, string $start_date, string $end_date ) {
	// $email_data = $this->messages->compose_weekly_report( $email, $weekly_stats, $start_date, $end_date );
	// if ( $email_data['enabled'] ) {
	// foreach ( $email_data['recipients'] as $recipient ) {
	// $this->mailer->send(
	// $recipient,
	// $email_data['subject'],
	// $email_data['content'],
	// $email_data['context'],
	// true // is_admin_email.
	// );
	// }
	//
	// do_action( 'wc_affiliate_email_send_weekly_report', $email, $weekly_stats, $start_date, $end_date );
	// }
	// }

	// **
	// * Send daily summary to admins
	// */
	// public function send_daily_summary() {
	// **
	// * Action hook fired before sending daily summary emails.
	// */
	// do_action( 'wc_affiliate_send_daily_summary_before' );
	//
	// $yesterday = wp_date( 'Y-m-d', strtotime( '-1 day' ) );
	//
	// Get yesterday's stats.
	// $stats = $this->get_daily_stats( $yesterday );
	//
	// if ( $stats['total_referrals'] > 0 || $stats['total_visits'] > 0 ) {
	// $admin_emails = wca_get_admin_emails();
	//
	// foreach ( $admin_emails as $email ) {
	// $this->send_daily_summary_email( $email, $stats, $yesterday );
	// }
	// }
	//
	// **
	// * Action hook fired after sending daily summary emails.
	// */
	// do_action( 'wc_affiliate_send_daily_summary_after' );
	// }
	//
	// **
	// * Get daily statistics
	// *
	// * @param string $date Date in 'Y-m-d' format.
	// *
	// * @return array Daily statistics.
	// */
	// public function get_daily_stats( string $date ): array {
	// $start_time = strtotime( $date . ' 00:00:00' );
	// $end_time   = strtotime( $date . ' 23:59:59' );
	//
	// Use Visit model to get visit count.
	// $visit_model  = new \WC_Affiliate\Models\Visit();
	// $total_visits = $visit_model->get_count(
	// array(
	// 'start_date' => $start_time,
	// 'end_date'   => $end_time,
	// )
	// );
	//
	// Use Referral model to get referral statistics.
	// $referral       = new \WC_Affiliate\Models\Referral();
	// $referrals_data = $referral->get_referrals(
	// array(
	// 'start_date' => $start_time,
	// 'end_date'   => $end_time,
	// 'limit'      => 0,
	// )
	// );
	//
	// $total_referrals   = count( $referrals_data );
	// $total_commissions = 0;
	// $top_affiliates    = array();
	//
	// Calculate total commissions and top affiliates.
	// $affiliate_stats = array();
	// foreach ( $referrals_data as $referral ) {
	// $total_commissions += $referral->get( 'commission' );
	//
	// $affiliate_id = $referral->get( 'affiliate' );
	// if ( ! isset( $affiliate_stats[ $affiliate_id ] ) ) {
	// $affiliate_stats[ $affiliate_id ] = array(
	// 'referral_count'   => 0,
	// 'total_commission' => 0,
	// );
	// }
	// ++$affiliate_stats[ $affiliate_id ]['referral_count'];
	// $affiliate_stats[ $affiliate_id ]['total_commission'] += $referral->get( 'commission' );
	// }
	//
	// Get top 5 affiliates.
	// arsort( $affiliate_stats );
	// $top_affiliates = array_slice( $affiliate_stats, 0, 5, true );
	//
	// return array(
	// 'total_visits'      => (int) $total_visits,
	// 'total_referrals'   => $total_referrals,
	// 'total_commissions' => (float) $total_commissions,
	// 'top_affiliates'    => $top_affiliates,
	// );
	// }
	//
	// **
	// * Send weekly reports
	// */
	// public function send_weekly_reports() {
	// **
	// * Action hook fired before sending weekly reports.
	// */
	// do_action( 'wc_affiliate_send_weekly_reports_before' );
	//
	// $start_date = wp_date( 'Y-m-d', strtotime( 'last monday', strtotime( '-1 week' ) ) );
	// $end_date   = wp_date( 'Y-m-d', strtotime( 'last sunday', strtotime( '-1 week' ) ) );
	//
	// $weekly_stats = $this->get_weekly_stats( $start_date, $end_date );
	//
	// $admin_emails = wca_get_admin_emails();
	//
	// foreach ( $admin_emails as $email ) {
	// $this->send_weekly_report_email( $email, $weekly_stats, $start_date, $end_date );
	// }
	//
	// **
	// * Action hook fired after sending weekly reports.
	// */
	// do_action( 'wc_affiliate_send_weekly_reports_after' );
	// }
	//
	// **
	// * Get weekly statistics
	// *
	// * @param string $start_date Start date in 'Y-m-d' format.
	// * @param string $end_date   End date in 'Y-m-d' format.
	// *
	// * @return array
	// */
	// public function get_weekly_stats( string $start_date, string $end_date ): array {
	// global $wpdb;
	//
	// $start_time = strtotime( $start_date . ' 00:00:00' );
	// $end_time   = strtotime( $end_date . ' 23:59:59' );
	//
	// Basic stats.
	// $stats = $this->get_period_stats( $start_time, $end_time );
	//
	// Conversion rate.
	// $stats['conversion_rate'] = $stats['total_visits'] > 0 ?
	// ( $stats['total_referrals'] / $stats['total_visits'] ) * 100 : 0;
	//
	// Top performing affiliates.
	// $stats['top_performers'] = $wpdb->get_results(
	// $wpdb->prepare(
	// "SELECT affiliate, COUNT(*) as referrals, SUM(commission) as commissions, SUM(order_total) as sales
	// FROM {$wpdb->prefix}wca_referrals
	// WHERE time BETWEEN %d AND %d
	// GROUP BY affiliate
	// ORDER BY commissions DESC
	// LIMIT 10",
	// $start_time,
	// $end_time
	// )
	// );
	//
	// return $stats;
	// }
	//
	// **
	// * Get statistics for a time period
	// *
	// * @param int $start_time Start timestamp.
	// * @param int $end_time   End timestamp.
	// *
	// * @return array Period statistics.
	// */
	// public function get_period_stats( int $start_time, int $end_time ): array {
	// global $wpdb;
	//
	// return array(
	// 'total_visits'      => (int) $wpdb->get_var(
	// $wpdb->prepare(
	// "SELECT COUNT(*) FROM {$wpdb->prefix}wca_visits WHERE time BETWEEN %d AND %d",
	// $start_time,
	// $end_time
	// )
	// ),
	// 'total_referrals'   => (int) $wpdb->get_var(
	// $wpdb->prepare(
	// "SELECT COUNT(*) FROM {$wpdb->prefix}wca_referrals WHERE time BETWEEN %d AND %d",
	// $start_time,
	// $end_time
	// )
	// ),
	// 'total_commissions' => (float) $wpdb->get_var(
	// $wpdb->prepare(
	// "SELECT SUM(commission) FROM {$wpdb->prefix}wca_referrals WHERE time BETWEEN %d AND %d",
	// $start_time,
	// $end_time
	// )
	// ),
	// 'total_sales'       => (float) $wpdb->get_var(
	// $wpdb->prepare(
	// "SELECT SUM(order_total) FROM {$wpdb->prefix}wca_referrals WHERE time BETWEEN %d AND %d",
	// $start_time,
	// $end_time
	// )
	// ),
	// );
	// }
}
